2015-11-18 44 views
2

我有過一些模型對象返回屬性的平均值的方法:如何使用流操作來計算列表中的值的平均值,省略一些?

List<Activity> activities = ...; 
double effortSum = 0; 
double effortCount = 0; 
activities.stream().forEach(a -> { 
    double effort = a.getEffort(); 
    if (effort != Activity.NULL) { 
     effortCount++;   < Compilation error, local variable 
     effortSum += effort;  < Compilation error, local variable 
    } 
}); 

但是,上述嘗試無法編譯,如上所述。唯一的解決方案是使用AtomicReferenceDouble對象,但這看起來十分骯髒,並且增加了大量的混淆,應該是是一個簡單的操作。 (或者添加番石榴並獲得AtomicDouble,但達到相同的結論。)

是否存在使用新的Java 8循環修改局部變量的「最佳實踐」策略?

的活動相關代碼:

public class Activity { 
    public static final double NULL = Double.MIN_VALUE; 

    private double effort = NULL; 

    public void setEffort(double effort) { this.effort = effort; } 
    public double getEffort() { return this.effort; } 

    ... 
} 
+0

你可以在你的OP中包含'activities'聲明嗎? –

+0

當然,我添加了相關的位。 –

回答

6

是否有一個 「最佳實踐」 的策略修改使用新的Java 8環路局部變量?

是:不。你可以修改它們的屬性 - 儘管它仍然是一個壞主意 - 但你不能自己修改它們;如果它們是final或者可能是final,則只能引用來自lambda內部的變量。 (AtomicDouble確實是一個解決方案,另一種是double[1],只是充當座)

在這裏實現了「平均」的正確的操作方法是

activities.stream() 
    .mapToDouble(Activity::getEffort) 
    .filter(effort -> effort != Activity.NULL) 
    .average() 
    .getAsDouble(); 
+0

啊,完美 - 中間'filter()'方法是_exactly_讓我擺脫這個泡菜。 –

4

在你的情況,有一個解決方案這是更多的功能 - 只需從流從那裏你可以抓住過濾元件的數量和它們的總和計算彙總統計:

DoubleSummaryStatistics stats = 
    activities.stream() 
       .mapToDouble(Activity::getEffort) 
       .filter(e -> e != Activity.NULL) 
       .summaryStatistics(); 

long effortCount = stats.getCount(); 
double effortSum = stats.getSum(); 

是否有一個「最佳練習「使用新的Java 8循環修改局部變量 的策略?

不要試圖做到這一點。我認爲主要的問題是人們試圖用命令式的方式使用新的Java 8特性來翻譯他們的代碼(就像在你的問題中 - 然後你有麻煩!)。

如果你能提供一個功能正常的解決方案(我相信這是Stream API的目標),試着先看看。

+0

謝謝 - 關於'summaryStatistics()'的TIL也是如此。 –

+2

順便說一句,我不會像'double [1]'持有人一樣使用變通辦法。只需並行轉換流即可運行併發問題。我只會讓代碼處於其必要的風格。 –