I'm trying to make a method that runs a series of steps defined by lambdas. The following code illustrates how I am doing it. However, the steps aren't executed in order. I thought about using LinkedHashMap instead of Map, but the lambda says Target type of a lambda conversion must be an interface
.
public class Test {
static void runSomeStuff(Map<String, CheckedRunnable> actions){
actions.forEach((name, action) -> {
System.out.println("Running " name "...");
try {
action.run();
} catch (Throwable e) {
throw new RuntimeException(e);
}
});
}
public static void main(String[] args) {
runSomeStuff(Map.of(
"Step 1", () -> {
System.out.println("1");
},
"Step 2", () -> {
System.out.println("2");
}
));
}
}
CodePudding user response:
You've not shared CheckedRunnable
but if you've declared such that your Map.of
works, then you should be able to pass in LinkedHashMap
such that the order of actions is preserved:
LinkedHashMap<String,CheckedRunnable> actions = new LinkedHashMap<>();
for (String s : List.of("Step X", "Step A", "Step N"))
actions.put(s, () -> System.out.println("Executing action: " s));
for (int i = 0 ; i < 20; i ) {
final int index = i;
actions.put("Item " index, () -> System.out.println("Executing #" index));
}
runSomeStuff(actions);
This should print:
Running Step X...
Executing action: Step X
Running Step A...
Executing action: Step A
Running Step N...
Executing action: Step N
Running Item 0...
Executing #0
...
Note that if runSomeStuff
is called with other Map implementations the order won't be the same as insertion.
CodePudding user response:
In this case, as mentioned in the comments, List
is a semantically more appropriate mean of storing the data because you're not accessing values through their keys, but simply iterating over the map entries.
Instead of using a map in order to fuse the two attributes together the intuitive and maintainable way of structure the data would be to define a custom object. Since Java 16 records it might be literally done with a single line of code.
record Action(String name, Runnable task) {}
List<Action> actions = List.of(
new Action("Step 1", () -> System.out.println(1)),
new Action("Step 2", () -> System.out.println(2))
);
But if you're convinced that you need a Map, in case if these tasks are as simple as you've described, you can generate using a plain index-based loop or a stream.
final int actionCount = 3;
Map<String, CheckedRunnable> actionByStepName = IntStream.rangeClosed(1, actionCount)
.boxed()
.collect(Collectors.toMap(
i -> "Step " i,
i -> () -> System.out.println(i),
(left, right) -> {
throw new AssertionError("duplicated keys are not expected");
},
LinkedHashMap::new
));