Lambda中使用的变量在计算总和时应该是最终的还是有效的?

时间:2017-08-22 01:00:57

标签: java-8

我有一张包含地图的地图。 地图> 对于地图中的所有条目,我想计算特定键的总和。

例如我的地图是这样的:

Key1    Key2    Value
A       Z       10.10
B       Z       40.10
C       Y       20.10

我想基本上计算所有key2的总和,它等于B.所以在这种情况下我想得到50.20因为Key1 -C没有key2 Z

我正在尝试使用Java 8.我不知道如何收集总和。

double sum = 0;
myMap.forEach((key1, key2) -> {
    sum += key2.get("Z");
});

但后来我得到一个错误,说lambda中的值应该是final。

4 个答案:

答案 0 :(得分:3)

匿名内部类或Lambda中使用的所有外部变量都必须是final or effectively final(永不重新分配的非最终变量)。

在您的解决方案中,您正尝试使用功能性解决方案来修复经典命令解决方案。

惯用的Java-8方法是使用Stream API:

map.values().stream()
  .map(x -> x.get("Z"))
  .reduce(0, Double::sum);

或将专门的Stream用于double s:

map.values().stream()
  .mapToDouble(x -> x.get("Z"))
  .sum()

请记住正确处理边缘情况。如果没有与“Z”键相关联的值,则会爆炸。

答案 1 :(得分:1)

您可以使用Stream。这样你也可以使用中间操作:

myMap.entrySet().stream()
                .filter(entry -> entry.getValue().equals(Z))
                .map(entry -> entry.getValue())
                .mapToDouble(v -> v.get("Z"))
                .sum()

我不确定您的数据结构,所以这可能需要一些工作,但我希望您明白这一点。

https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html

您的方法不起作用,因为您尝试在无法修改的范围内修改局部变量。见http://docs.oracle.com/javase/tutorial/java/javaOO/localclasses.html

tl; dr您无法修改lambda体中的局部变量。

答案 2 :(得分:0)

你得到了如何正确地(你的例子)用流做的答案。有时候这是不可行的(即使在jdk源代码中也存在需要数组包装器的地方):

double [] sum = {0};
myMap.forEach((key1, key2) -> {
   sum[0] += key2.get("Z");
});

答案 3 :(得分:0)

或者您可以使用AtomicInteger,它是threadSafe