Java 8 - 在列表中存储 lambda
Java 8 - store lambdas in List
我想知道是否可以将 lambda 存储在某个容器中,例如。 ArrayList 或 HashMap。
我想更改该代码:
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);
}
}
类似于:
List<BinaryOperator<Integer>> opcodes = new ArrayList<BinaryOperator<Integer>>(){
((x, y) -> y),
((x, y) -> ++x)
};
等等
并像这样使用它:
opcodes[0].apply(a, b);
甚至可能吗?
您当然可以创建这样的列表:
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
或者纠正您尝试初始化列表的方式
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);
}};
因此,一旦你可以做这样的事情,你就已经定义了你的操作员:
List<BinaryOperator<Integer>> opcodes = new ArrayList<BinaryOperator<Integer>>() {{
add(OPCODE.ADD);
add(OPCODE.DEC);
}};
在您的主要方法中进行测试:
opcodes.forEach(elm -> System.out.println(elm.apply(1,2)));
在@nullpointer 的额外回答中,您还可以考虑使用 Map
键来保留函数的原始 OPCODE
意图,这将是数组中的 lst,例如使用 Enum
作为键:
public enum OPCODES {
MOV, ADD, XOR
}
可以自举的:
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);
并使用:
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));
是的,您可以将 lambda 表达式放入列表或映射的值中。请记住,lambda 只是一种编写匿名 类 的奇特方式,而后者又只是 new
运算符的一个特例。换句话说,operators.add((x, y) -> x + y)
只是 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);
按照同样的逻辑,operatorMap.put("add", (x, y) -> x + y);
也会完全按照您的预期进行。
但是,将 lambda 放入集合中 - 包括将它们用作映射键 - 可能无法达到您的预期。通常,集合的行为取决于其元素类型对 equals
和 hashCode
的定义,并且语言不对这些方法提供任何超出 [=18 定义所要求的内容的保证=].因此,以下断言可能会失败:
final Function<Object, String> func1 = Object::toString;
final Function<Object, String> func2 = Object::toString;
assert func1.equals(func2);
同样如下:
final Function<Object, String> func = Object::toString;
final Set<Object> set = new HashSet<>();
set.add(func);
assert set.contains(Object::toString);
所以,小心地将 lambda 放入基于 Set
的容器中,包括用作 Map
键,但它们可以放入 List
并用作 Map
值就好了。
您可以将 lambda 存储在容器中,但真正的问题是您为什么要这样做?将它们存储在 List
中很容易,例如 Set/Map
怎么样 - 你不能为 lambda 覆盖 equals/hashcode
- 所以你不知道会发生什么。
既然你已经有了一个Enum
,为什么不使用更简单的方法:
Set<OPCODE> set = EnumSet.allOf(OPCODE.class);
细化@naomimyselfandi 的回答。
你可以用一些柯里化魔法来规范 Function
:
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)
);
见
@Holger 评论:
我想知道是否可以将 lambda 存储在某个容器中,例如。 ArrayList 或 HashMap。 我想更改该代码:
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);
}
}
类似于:
List<BinaryOperator<Integer>> opcodes = new ArrayList<BinaryOperator<Integer>>(){
((x, y) -> y),
((x, y) -> ++x)
};
等等
并像这样使用它:
opcodes[0].apply(a, b);
甚至可能吗?
您当然可以创建这样的列表:
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
或者纠正您尝试初始化列表的方式
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);
}};
因此,一旦你可以做这样的事情,你就已经定义了你的操作员:
List<BinaryOperator<Integer>> opcodes = new ArrayList<BinaryOperator<Integer>>() {{
add(OPCODE.ADD);
add(OPCODE.DEC);
}};
在您的主要方法中进行测试:
opcodes.forEach(elm -> System.out.println(elm.apply(1,2)));
在@nullpointer 的额外回答中,您还可以考虑使用 Map
键来保留函数的原始 OPCODE
意图,这将是数组中的 lst,例如使用 Enum
作为键:
public enum OPCODES {
MOV, ADD, XOR
}
可以自举的:
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);
并使用:
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));
是的,您可以将 lambda 表达式放入列表或映射的值中。请记住,lambda 只是一种编写匿名 类 的奇特方式,而后者又只是 new
运算符的一个特例。换句话说,operators.add((x, y) -> x + y)
只是 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);
按照同样的逻辑,operatorMap.put("add", (x, y) -> x + y);
也会完全按照您的预期进行。
但是,将 lambda 放入集合中 - 包括将它们用作映射键 - 可能无法达到您的预期。通常,集合的行为取决于其元素类型对 equals
和 hashCode
的定义,并且语言不对这些方法提供任何超出 [=18 定义所要求的内容的保证=].因此,以下断言可能会失败:
final Function<Object, String> func1 = Object::toString;
final Function<Object, String> func2 = Object::toString;
assert func1.equals(func2);
同样如下:
final Function<Object, String> func = Object::toString;
final Set<Object> set = new HashSet<>();
set.add(func);
assert set.contains(Object::toString);
所以,小心地将 lambda 放入基于 Set
的容器中,包括用作 Map
键,但它们可以放入 List
并用作 Map
值就好了。
您可以将 lambda 存储在容器中,但真正的问题是您为什么要这样做?将它们存储在 List
中很容易,例如 Set/Map
怎么样 - 你不能为 lambda 覆盖 equals/hashcode
- 所以你不知道会发生什么。
既然你已经有了一个Enum
,为什么不使用更简单的方法:
Set<OPCODE> set = EnumSet.allOf(OPCODE.class);
细化@naomimyselfandi 的回答。
你可以用一些柯里化魔法来规范 Function
:
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)
);
见
@Holger 评论: