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

Java 如何使用流操作计算列表中的值的平均值,而忽略一些值?,java,foreach,java-8,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++;

我有一个方法可以返回多个模型对象上属性的平均值:

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
    }
});
是否有使用新的Java8循环修改局部变量的“最佳实践”策略

是的,不要。你可以修改它们的属性——尽管这仍然是个坏主意——但你不能自己修改它们;如果变量是
final
或可以是
final
,则只能从lambda内部引用变量。(
AtomicDouble
确实是一种解决方案,另一种是只充当持有者的
double[1]

这里执行“平均”操作的正确方法是

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

在您的情况下,有一个更实用的解决方案-只需从流中计算摘要统计信息,您就可以从中获取过滤的元素数量及其总和:

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

long effortCount = stats.getCount();
double effortSum = stats.getSum();
是否有修改局部变量的“最佳实践”策略 使用新的Java8循环

不要试图那样做。我认为主要的问题是,人们试图以一种强制性的方式使用新的Java8特性来翻译他们的代码(就像在你的问题中——然后你就有麻烦了!)


首先尝试看看您是否可以提供一个功能性的解决方案(我相信这就是StreamAPI的目标)

你能在你的OP中加入
活动的声明吗?当然,我添加了相关的位。啊,完美-中间
过滤器()
方法正是让我摆脱这个困境的方法。谢谢-直到
summaryStatistics()
。顺便说一句,我不会像
双[1]
持有者那样使用变通方法。只要将流并行运行,就足以解决并发问题。我将让代码以命令式的方式运行。
DoubleSummaryStatistics stats = 
    activities.stream()
              .mapToDouble(Activity::getEffort)
              .filter(e -> e != Activity.NULL)
              .summaryStatistics();

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