我喜歡的建議減量使用,但也許一個更完整的答案會說明爲什麼這是一個好主意。
在lambda表達式中,您可以引用變量,如output
,它們在定義lambda表達式的範圍內,但不能修改這些值。原因在於,在內部,編譯器必須能夠通過創建一個以lambda作爲其主體的新函數來實現您的lambda,如果它選擇這樣做的話。編譯器可以根據需要選擇添加參數,以便在生成的函數中使用的所有值在參數列表中可用。在你的情況下,這樣的函數肯定會有lambda的顯式參數testEnum
,但是因爲你也可以在lambda體中引用局部變量output
,所以它可以將其作爲第二個參數添加到生成的函數中。實際上,編譯器可能會產生從拉姆達此功能:
private void generatedFunction1(TestEnum testEnum, int output) {
output |= testEnum.getValue();
}
正如你所看到的,output
參數是由主叫方使用的output
變量的副本,或運算將只適用於複製。由於原來的output
變量不會被修改,因此語言設計者決定禁止修改隱式傳遞給lambda的值。
要解決的最直接的方式問題,就目前的使用量減少的是一個更好的辦法,撇開,你可以換一個包裝的output
變量(例如int[]
數組大小1或中AtomicInteger
。包裝的引用將按值傳遞給生成的函數,並且由於您現在將更新output
的內容,因此output
,output
的值仍然有效,因此編譯器不會抱怨。例如:
AtomicInteger output = new AtomicInteger();
setOfEnums.stream().forEach(testEnum -> (output.set(output.get() | testEnum.getValue()));
或者,因爲我們使用的AtomicInteger,我們不妨讓它線程安全的情況下,以後你選擇使用並行Stream
,
AtomicInteger output = new AtomicInteger();
setOfEnums.stream().forEach(testEnum -> (output.getAndUpdate(prev -> prev | testEnum.getValue())));
現在我們」我已經回答了一個最類似於你所問的答案,我們可以談論使用減少的優越解決方案,其他答案已經被推薦。
有兩種通過Stream
提供的減少,無國籍減少(reduce()
和狀態還原(collect()
)。爲了顯現差異,考慮傳送帶提供漢堡包,和你的目標是收集所有的漢堡肉餅成一個大的漢堡包,有了狀態的減少,你會從一個新的漢堡麪包開始,然後在每個漢堡包到達時收集這些餅乾,然後將它添加到你設置的漢堡麪包堆中以收集它們。在無狀態的減少中,你首先用一個空的漢堡麪包(稱爲「身份」,因爲如果輸送帶是空的,那麼空漢堡麪包就是最終的結果),並且當每個漢堡包到達帶上時,以前累積的漢堡的副本,並添加新的餅乾,只是一個激發了,丟棄了以前積累的漢堡。
無狀態減少可能看起來像一個巨大的浪費,但有些情況下,複製累計值非常便宜。其中一種情況是積累原始類型 - 原始類型的拷貝非常便宜,因此在處理諸如求和,ORing等應用程序中的基元時,無狀態簡化是理想的。因此,使用無狀態約簡,您的示例可能會變成:
setOfEnums.stream()
.mapToInt(TestEnum::getValue) // or .mapToInt(testEnum -> testEnum.getValue())
.reduce(0, (resultSoFar, testEnum) -> resultSoFar | testEnum);
的幾點思考:
- 您的循環原來可能比使用流得更快,但也許如果你的設置是非常大的,你使用並行流。爲了使用流,請勿使用流。如果它們有意義,請使用它們。
- 在我的第一個例子中,我展示了使用
Stream.forEach()
。如果您發現自己創建了Stream
並且只需撥打forEach()
,則直接在集合上調用forEach()
效率更高。
- 你沒有提及你正在使用什麼樣的
Set
,但我希望你使用的是EnumSet<TestEnum>
。因爲它是作爲一個位域來實現的,所以對於所有的操作,甚至複製,它都比其他類型的Set
好得多(O(1))。 EnumSet.noneOf(TestEnum.class)
創建一個空Set
,EnumSet.allOf(TestEnum.class)
爲您提供了一組所有枚舉值等
您可以使用'.reduce(0,(e1,e2) - > e1 | e2)'的形式提供身份。或者,而不是'get'做一個'orElse(0)' – Eugene
@Eugene是的,這將是更好的情況下像空Setofenums否則可選將拋出異常,我會修改它。 –