Java 8 - 在List中存储lambdas

时间:2017-10-28 08:19:08

标签: lambda java-8 containers lookup-tables binary-operators

我想知道是否可以将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);

甚至可能吗?

6 个答案:

答案 0 :(得分:12)

您当然可以创建以下列表:

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);
}};

答案 1 :(得分:9)

在@ nullpointer的其他答案中,您还可以考虑使用Map键来保留函数的原始OPCODE意图,这些函数将在数组中保留,例如:使用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));

答案 2 :(得分:3)

可以将lambda存储在容器中,但真正的问题是你为什么要这样做呢?将它们存储在List中很简单,例如Set/Map如何 - 您无法覆盖equals/hashcode的lambdas - 因此您无法告诉会发生什么。

由于您已经有Enum,为什么不使用更简单的方法:

Set<OPCODE> set = EnumSet.allOf(OPCODE.class);

答案 3 :(得分:2)

因此,一旦你可以做这样的事情,你已经定义了你的算子:

List<BinaryOperator<Integer>> opcodes = new ArrayList<BinaryOperator<Integer>>() {{
    add(OPCODE.ADD);
    add(OPCODE.DEC);
}};

在您的主要方法中测试:

opcodes.forEach(elm -> System.out.println(elm.apply(1,2)));

答案 4 :(得分:0)

是的,您可以将lambdas放在列表或地图的值中。请记住,lambdas只是编写匿名类的一种奇特方式,而这只是new运算符的一个特例。换句话说,operators.add((x, y) -> x + y)只是

的简写
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);也会完全符合你的期望。

然而,将lambdas放入一个集合中 - 包括将它们用作地图键 - 可能无法达到预期效果。一般来说,集合的行为取决于equalshashCode的元素类型的定义,并且语言不会对这些方法做出任何超出“强制要求”的保证。 Object的定义。因此,以下断言可能会失败:

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);

因此,小心将lambdas放入基于Set的容器中,包括用作Map个键,但可以将它们放入List并用作Map值很好。

答案 5 :(得分:0)

细读@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评论: Can a java lambda have more than 1 parameter?