Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to map lambda expressions in Java

I'm coming from Python, and trying to understand how lambda expressions work differently in Java. In Python, you can do stuff like:

opdict = { "+":lambda a,b: a+b, "-": lambda a,b: a-b, 
           "*": lambda a,b: a*b, "/": lambda a,b: a/b }
sum = opdict["+"](5,4) 

How can I accomplish something similar in Java? I have read a bit on Java lambda expressions, and it seems I have to declare an interface first, and I'm unclear about how and why you need to do this.

Edit: I attempted to do this myself with a custom interface. Here's the code I have tried:

Map<String, MathOperation> opMap = new HashMap<String, MathOperation>(){
        { put("+",(a,b)->b+a);
          put("-",(a,b)->b-a);
          put("*",(a,b)->b*a);
          put("/",(a,b)->b/a); }
};
...
...

interface MathOperation {
   double operation(double a, double b);
}

However, this gives an error:

The target type of this expression must be a functional interface.

Where exactly do I declare the interface?

like image 464
b_pcakes Avatar asked Oct 11 '15 22:10

b_pcakes


People also ask

What is map in lambda expression Java?

A Map is a collection object that maps keys to values in Java. The data can be stored in key/value pairs and each key is unique. These key/value pairs are also called map entries.

What does map () do in Java?

A Map is an object that maps keys to values. A map cannot contain duplicate keys: Each key can map to at most one value. It models the mathematical function abstraction.

What is the purpose of map () method of stream in Java 8?

Java 8 Stream's map method is intermediate operation and consumes single element forom input Stream and produces single element to output Stream. It simply used to convert Stream of one type to another.


2 Answers

Easy enough to do with a BiFunction in Java 8:

final Map<String, BiFunction<Integer, Integer, Integer>> opdict = new HashMap<>();
opdict.put("+", (x, y) -> x + y);
opdict.put("-", (x, y) -> x - y);
opdict.put("*", (x, y) -> x * y);
opdict.put("/", (x, y) -> x / y);

int sum = opdict.get("+").apply(5, 4);
System.out.println(sum);

The syntax is a bit more verbose than Python to be sure, and using getOrDefault on opdict would probably be preferable as to avoid a scenario in which you use an operator that doesn't exist, but this should get the ball rolling at least.

If you're exclusively working with ints, using IntBinaryOperator would be preferable, as this would take care of any generic typing that you'd have to do.

final Map<String, IntBinaryOperator> opdict = new HashMap<>();
opdict.put("+", (x, y) -> x + y);
opdict.put("-", (x, y) -> x - y);
opdict.put("*", (x, y) -> x * y);
opdict.put("/", (x, y) -> x / y);

int sum = opdict.get("+").applyAsInt(5, 4);
System.out.println(sum);
like image 180
Makoto Avatar answered Oct 19 '22 22:10

Makoto


An alternative solution is to use an enum:

public enum Operation {
    PLUS((x, y) -> x + y),
    MINUS((x, y) -> x - y),
    TIMES((x, y) -> x * y),
    DIVIDE((x, y) -> x / y);

    private final IntBinaryOperator op;

    Operation(IntBinaryOperator op) { this.op = op; }

    public int apply(int x, int y) { return op.applyAsInt(x, y); }
}

Then you can do:

int sum = Operation.PLUS.apply(5, 4);

This is not as succinct as other solutions, but using an enum rather than a String means that when you type Operation. into an IDE, you will be presented with the list of all possible operations.

like image 33
Paul Boddington Avatar answered Oct 19 '22 22:10

Paul Boddington