Sudheer Sudheer - 2 days ago 4
Java Question

Refactor a switch case with java lambdas

I am trying to re-factor a legacy code and in this case I have a huge block of switch case which decide which command to be executed

switch(operation)
case addition : return add(int a, String b, String c);
case multiply : return multiply(int a, int b);
case substract : return substract(int a, int b);


Approach 1 : using polymorphism

public interface Operation {
void performOperation(int a, int b);
}


Then fill a map with the available implementations:

Map<Key, Operation> actions = new HashMap<>();
actions.add(addition, new addOperation());
actions.add(multiply, new multiplyOperation());
actions.add(substract, new substractOperation());


Then I can refer the map when I need to perform a operation.

The issues I have with this approach is that I am having to create a large number of classes / annonymous classes

Approach 2 : Using Enum

public enum MyKeyEnum {
ADDITION {
public void performOperation(int a, int b) {
// Perform addition
}
},
MULTIPLY {
public void performOperation(int a, int b) {
// Perform Multiplication
}
};

public abstract void performOperation(int counter, String dataMain, String dataSub);
}


This approach is actually better of the two but I saw another eaxmple in Java 8 and want use something like this

As all these are following a pattern I tried to use Functional Interface and Maps

final static Map<String, Supplier<IAction>> map = new HashMap<>();
static {
map.put("add", Addition::new);
map.put("multiply", Multiply::new);
}
public static void main(String[] args) throws Exception {
Supplier<IAction> action = map.get("add");
System.out.println(action.get().performAction(10,10));

action = map.get("multiply");
System.out.println(action.get().performAction(10,10));
}


But this again has the disadvantages of the first approach so wanted to see if I can use lambdas like I used Enum implementation
There is a partial function implementation provided in Java 8 which I wanted to utilize
Example :

BiFunction<Integer, Integer, Integer> minus = (x, y) -> x - y;
Function<Integer, Integer> subtractor = partial(minus, 10);
System.out.println(subtractor.apply(4)); // 6


as BiFunction is accepting only 2 parameters I created a Trifuction like

@FunctionalInterface
interface TriFunction<T, U, V, R> {
R apply(T a, U b, V c);
}

public static <T, U, V, R> Function<V, R> partial(TriFunction<T, U, V, R> f, T x, U y) {
return (z) -> f.apply(x, y, z);
}


This will resolve the issue to an extent but I am not able to figure out how I can add this to the map and dynamically pass values

Map<String, TriFunction<String, Integer, Integer, Operation>> map
= new HashMap<>();

Answer

You are already there. If you've a method which has the same signature of your interface you can also pass it to your operation repository like:

Map<String, IntBinaryOperator> operations = new HashMap<>();
operations.put("add", Integer::sum);
operations.put("subtract", (a, b) -> a - b);
operations.put("multiply", (a, b) -> a * b);
//...
System.out.println(operations.get("multiply").applyAsInt(10, 20));
Comments