2017-10-28 64 views
13

我想知道是否有可能将lambda存储在某个容器中,例如。 ArrayList或HashMap。 我想改变这种代码:Java 8 - 在列表中存储lambdas

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

甚至有可能?

+4

作为一个侧面说明,您的操作'INC'和'DEC'可能没有预期的效果,因为Java是呼叫因为修改参数并不会改变调用者端的任何值,所以'(x,y) - > ++ x'是一种误导性的方式来形成'(x,y) - > x + 1'和同样'(x,y) - > - x'实际上也是'(x,y) - > x-1'。 – Holger

+0

所以真的这个问题只是问(1)如何使用一个'List'和(2)如何实例化具有给定元素的'ArrayList' ... – MCMastery

+0

@Holger即使IDE应该在那里触发警告(如果OP是使用一个) – Eugene

回答

11

当然,您可以创建这样一个列表如下:

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

你子类的写opcodes列表的方式使得每次使用该方法时都会创建另一个子类,这真的是效率低下 – Ferrybig

+0

@Ferrybig你的意思是'Arrays.asList'初始化吗?没有把你带到那里。 – nullpointer

+1

谢谢,完全忘了Arrays.asList()。我有建议更改助记符以清除数字,因为这种方式更现实。那么,助记符转移到评论然后:> – Jump3r

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

嗯,我相信这个想法是改变它,而不是重复使用。但仍然有效,我会说。尽管现在DS中的任何一个都没有被这种方法所用。 – nullpointer

+1

@nullpointer thx您的意见,我同意。 –

+0

你可以减少而不是forEeching来实现这个结果@nullpointer –

9

在附加@空指针的伟大答案,你也可以考虑使用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)); 
+0

我的意思是操作符的意图是数组'丢失',除非定义了MOV,INC等顺序索引0,1,2的常量 – StuartLC

0

是的,你可以把地图列表中的lambda表达式或值正好。请记住,lambda只是写匿名类的一种奇特方式,而这只是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);也会做你期望什么。

但是,将lambda放入一个集合 - 其中包括使用它们作为映射键 - 可能不会达到您的预期。通常,集合的行为取决于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); 

所以,要小心把lambda表达式为Set基于容器,包括用作Map键,但也可以是放入List s并用作Map值就好了。

3

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

既然你已经有一个Enum在那里,为什么不使用更简单的方法:

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