Java 8 Map<String, Runnable> Control Flow

1.9k Views Asked by At

I'm trying to familiarize myself with some new Java 8 functionality (ha) but I'm having some control flow mishaps.

In the following code, I have a Map<String, Runnable> so I can call methods based on their name, but I can't seem to figure out how to do two things:

  1. How can I make these methods take parameters? I.e. what is the syntax I need in the map "put"s.
  2. When I call these methods from the "get" method in "Dispatch, I cannot return the return value of the method (Status). I suspect this has something to do with where the method is being called, but I can't figure it out. Status is just an enum and the toList method just takes a space separated string and returns a list (this is meant to be used as a REPL).

import java.util.*;

public class Dispatcher {
    private Map<String, Runnable> func;
    private Status status;
    private List<String> command;
    Optional<List<String>> opt;

    public Dispatcher() {
        func = new HashMap<>();
        func.put("Method1", this::Method1);
        func.put("Method2", this::Method2);
        func.put("Help", this::Help);
        status = Status.DONE;
    }

    private Status Help() {
        return Status.DONE;
    }

    private Status Method1() {
        return Status.DONE;
    }

    private Status Method2() {
        return Status.DONE;
    }

    /**
     * Execute the given command on a new process.
     * @param command the full command requested by the caller including command name and arguments.
     * @return The status of the requested operation.
     */
    public Status Dispatch(String command) {
        opt = CommandInterpreter.toList(command);
        opt.orElse(new LinkedList<String>(){{add("Help");}});
        func.get(opt.get().get(0));
        return Status.DONE;
    }
}
3

There are 3 best solutions below

0
On BEST ANSWER

Here is a skeleton how you may start do deal with commands taking zero or more arguments and returning a status code. It is just a blueprint, an example. Perhaps it helps you getting started:

public class Dispatcher {

    public static final int SUCCESS = 0;

    public static final int FAILURE = 1;

    public static final Command HELP = (args) -> {
        String command = args[0];
        System.out.println("Usage of " + command + ": bla bla");
        return FAILURE;
    };

    public static final Command RENAME = (args) -> {
        File oldName = new File(args[1]);
        File newName = new File(args[2]);
        return oldName.renameTo(newName) ? SUCCESS : FAILURE;
    };

    public final Map<String, Command> commands = new HashMap<String, Command>() {{
        put("help", HELP);
        put("rename", RENAME);
    }};

    public int dispatch(String commandLine) {
        String[] args = commandLine.split("\\s");
        return Optional.ofNullable(commands.get(args[0]))
                .orElse(HELP)
                .execute(args);
    }
}

interface Command {
    int execute(String... args);
}
0
On

If you want the methods to take arguments, then you don't want to store it as Runnable. You might want Consumer, or another custom functional interface that accepts an argument -- if you want a return value, use Function, or create your own interface.

0
On

The Runnable interface doesn't accept any parameters or have a return type. To add a return type, you can use Supplier<Status>. To add a parameter, use Function<ParamType, Status>.