2017-10-28 97 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);