2014-03-25 130 views
3

這個問題是後續前面一個問題:Adding up BigDecimals using Streams在Java中8避免NoSuchElementException異常流

相關加起來使用Java 8 Stream S和Lambda表達式BigDecimal S上的問題。在實現給出的答案後,我遇到了另一個問題:每當流爲空時,Optional::get()方法拋出NoSuchElementException

考慮下面的代碼:

public static void main(String[] args){ 
    LinkedList<BigDecimal> values = new LinkedList<>(); 
//  values.add(BigDecimal.valueOf(.1)); 
//  values.add(BigDecimal.valueOf(1.1)); 
//  values.add(BigDecimal.valueOf(2.1)); 
//  values.add(BigDecimal.valueOf(.1)); 

    // Classical Java approach 
    BigDecimal sum = BigDecimal.ZERO; 
    for(BigDecimal value : values) { 
     System.out.println(value); 
     sum = sum.add(value); 
    } 
    System.out.println("Sum = " + sum); 

    // Java 8 approach 
    values.forEach((value) -> System.out.println(value)); 
    System.out.println("Sum = " + values.stream().reduce((x, y) -> x.add(y)).get()); 
} 

香草Java代碼有一個空的收集沒有問題,但新的Java 8代碼一樣。

在這裏避免NSEE的最優雅的方式是什麼?當然我們可以這樣做:

System.out.println("Sum = " + values == null || values.isEmpty() ? 0 : values.stream().reduce((x, y) -> x.add(y)).get()); 

但是有沒有Java-8-ish方法來處理空集合?

+0

逆序:values.stream()。reduce((x,y) - > x.add(y))。ifPresent(s - > System.out.println(「sum =」+ s)); //只有在有價值時纔打印總和。 –

回答

4

打字時的例子要問的問題,我找到了答案:

Stream::reduce()返回Optional其中有一個方法:orElse()。所以,

System.out.println("Sum = " + values.stream().reduce((x, y) -> x.add(y)).get()); 

成爲

System.out.println("Sum = " + values.stream().reduce((x, y) -> x.add(y)).orElse(BigDecimal.ZERO)); 

所以我決定發佈Q-和-A。

蘭巴達斯是偉大的。 +1 Java。

+0

你看過另一個答案,它使用重載'reduce()'方法,傳遞'BigDecimal.ZERO'作爲第一個參數嗎?該方法只返回一個'BigDecimal',而不是'Optional'。 –

+5

錯誤是在可選項上調用get(),但您不知道該對象是非空的。而應使用其中一個條件方法,如orElse()或ifPresent(),或者根據Optional.isPresent()編寫條件代碼。 –

6

在這種情況下,您應該使用版本爲reduce而不是,該版本可以返回Optional<BigDecimal>

如前所述,您應該使用另一個版本,該版本在流爲空的情況下提供標識元素,這是標識元素存在的全部原因。

所以,你想有:

System.out.println("Sum = " + values.stream().reduce(BigDecimal.ZERO, (x, y) -> x.add(y)); 

,而不是舊版本。

在這種情況下,你不關心流是否爲空,你只是想要一個有效的結果。

+0

嗯,這就是身份價值的原因嗎?當流不爲空時,身份值是否會執行任何操作? 「Stream」類提供的無數選項可能會造成混淆。 – ryvantage

+0

@ryvantage在您的Java 7代碼的for循環之前,標識值等於您的BigDecimal sum = BigDecimal.ZERO;'。 – skiwi

+2

是的,這裏有兩個arg'reduce'形式(帶有標識值)。身份值不僅在零元素流的情況下使用,而且在進行並行縮減時也用作部分結果的初始值。 –