如何使用流操作来计算列表中的平均值,省略一些?

Cra*_*tis 2 java foreach java-8

我有一个方法,它返回一个属性的平均值超过许多模型对象:

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
    }
});
Run Code Online (Sandbox Code Playgroud)

但是,如上所述,上述尝试无法编译.我遇到的唯一解决方案是使用AtomicReference一个Double对象,但这看起来很苛刻,并且会给应该是一个简单的操作带来大量的混淆.(或者加入番石榴并获得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; }

    ...
}
Run Code Online (Sandbox Code Playgroud)

Lou*_*man 6

是否有使用新Java 8循环修改局部变量的"最佳实践"策略?

是的:不要.你可以修改它们的属性 - 虽然它仍然是一个坏主意 - 但你不能自己修改它们; 你只能从lambda内部引用变量,如果它们是final或可能的话final.(AtomicDouble确实是一种解决方案,另一种解决方案double[1]只是作为持有者.)

这里实现"平均"操作的正确方法是

activities.stream()
    .mapToDouble(Activity::getEffort)
    .filter(effort -> effort != Activity.NULL)
    .average()
    .getAsDouble();
Run Code Online (Sandbox Code Playgroud)