Reputation: 1028
I wonder if it's possible to store lambdas in some container, for ex. ArrayList or HashMap. I want to change that code:
public enum OPCODE implements BinaryOperator<Integer> {
MOV((x, y) -> y),
INC((x, y) -> ++x),
DEC((x, y) -> --x),
ADD((x, y) -> x + y),
SUB((x, y) -> x - y);
private final BinaryOperator<Integer> binaryOperator;
OPCODE(BinaryOperator<Integer> binaryOperator) {
this.binaryOperator = binaryOperator;
}
@Override
public Integer apply(Integer integer, Integer integer2) {
return binaryOperator.apply(integer, integer2);
}
}
To something like:
List<BinaryOperator<Integer>> opcodes = new ArrayList<BinaryOperator<Integer>>(){
((x, y) -> y),
((x, y) -> ++x)
};
etc.
and use it like so:
opcodes[0].apply(a, b);
It is even possible?
Upvotes: 16
Views: 8203
Reputation: 11431
Refining on @naomimyselfandi's answer.
You can use regular Function
with some currying magic:
List<Function<Integer, Function<Integer, Integer>>> opcodes = Arrays.asList(
(x -> y -> y),
(x -> y -> ++x),
(x -> y -> --x),
(x -> y -> x + y),
(x -> y -> x - y)
);
Please refer below for more details.
@Holger comment on: Can a java lambda have more than 1 parameter?
Upvotes: 0
Reputation: 120848
You could store lambdas inside a container, but the real question is why would you want to do that? Storing them in a List
is easy, what about a Set/Map
for example - you can't override equals/hashcode
for lambdas - so you can't tell what would happen.
Since you already have an Enum
there, why not use the simpler method:
Set<OPCODE> set = EnumSet.allOf(OPCODE.class);
Upvotes: 3
Reputation: 355
Yes, you can put lambdas in a list or values of a map just fine. Remember that lambdas are just a fancy way of writing anonymous classes, which in turn are just a special case of the new
operator. Put another way, operators.add((x, y) -> x + y)
is just shorthand for
final BinaryOperator<Integer> ADD = new BinaryOperator<Integer>() {
@Override
public Integer apply(final Integer x, final Integer y) {
return x + y;
}
};
operators.add(ADD);
By the same logic, operatorMap.put("add", (x, y) -> x + y);
would also do exactly what you expect.
However, putting lambdas into a set - which includes using them as map keys - might not do what you expect. Generally, the behavior of a set depends on the definition of equals
and hashCode
by its element type, and the language doesn't make any guarantees for those methods beyond what's mandated by the definition of Object
. Therefore, the following assert can fail:
final Function<Object, String> func1 = Object::toString;
final Function<Object, String> func2 = Object::toString;
assert func1.equals(func2);
Likewise the following:
final Function<Object, String> func = Object::toString;
final Set<Object> set = new HashSet<>();
set.add(func);
assert set.contains(Object::toString);
So, be careful putting lambdas into Set
-based containers, including use as Map
keys, but they can be put into List
s and used as Map
values just fine.
Upvotes: 0
Reputation: 107247
In additional @nullpointer's great answer, you can also consider using a Map
key to retain the original OPCODE
intention of the functions, which would be lst in the array, e.g. using an Enum
as a key:
public enum OPCODES {
MOV, ADD, XOR
}
Which can be bootstrapped:
Map<OPCODES, BinaryOperator<Integer>> opcodeMap =
new EnumMap<OPCODES, BinaryOperator<Integer>>(OPCODES.class);
opcodeMap.put(OPCODES.ADD, (x, y)-> x + y);
opcodeMap.put(OPCODES.MOV, (x, y) -> y);
opcodeMap.put(OPCODES.XOR, (x, y) -> x ^ y);
And used:
System.out.println(opcodeMap.get(OPCODES.ADD).apply(1, 2));
System.out.println(opcodeMap.get(OPCODES.MOV).apply(1, 2));
System.out.println(opcodeMap.get(OPCODES.XOR).apply(1, 2));
Upvotes: 9
Reputation: 33397
Hence you have defined your operator once you can do some thing like this:
List<BinaryOperator<Integer>> opcodes = new ArrayList<BinaryOperator<Integer>>() {{
add(OPCODE.ADD);
add(OPCODE.DEC);
}};
to test that in your main method:
opcodes.forEach(elm -> System.out.println(elm.apply(1,2)));
Upvotes: 2
Reputation: 31878
You can certainly create such a list as:
List<BinaryOperator<Integer>> opcodes = Arrays.asList((x, y) -> y, (x, y) -> ++x);
// sample
int a=14,b=16;
System.out.println(opcodes.get(0).apply(a, b)); // prints 16
System.out.println(opcodes.get(1).apply(a, b)); // prints 15
Or redressing the way you were trying to initializing the list
List<BinaryOperator<Integer>> opcodes = new ArrayList<BinaryOperator<Integer>>() {{
add((x, y) -> y);
add((x, y) -> ++x);
add((x, y) -> --x);
add((x, y) -> x + y);
add((x, y) -> x - y);
}};
Upvotes: 12