stream.foreach中的java 8局部变量

时间:2018-03-14 08:46:31

标签: java lambda java-8 java-stream local-variables

我想在lambda函数中使用局部变量,但是我得到错误: 请参阅代码中的1.和2.点。

class Foo {
    int d = 0; // 1. It compiles, but ugly, 2. doesnt compile
    public void findMax(List<List<Route>> routeLists) {
        int d = 0; // 2.Error : Local variable dd defined in an enclosing scope must be final or effectively final
        routeLists.forEach(e-> {
            e.forEach(ee -> {
                d+=ee.getDistance();    
            });

        });
        ... doing some other operation with d
    }
}

如何使用它们将它们设置为全局变量?

3 个答案:

答案 0 :(得分:6)

forEach是错误的工具。

int d =
    routeLists.stream()                // Makes a Stream<List<Route>>
        .flatMap(Collection::stream)   // Makes a Stream<Route>
        .mapToInt(Route::getDistance)  // Makes an IntStream of distances
        .sum();

或者只使用嵌套for循环:

int d = 0;
for (List<Route> rs : routeLists) {
  for (Route r : rs) {
    d += r.getDistance();
  }
}

答案 1 :(得分:1)

在流中使用的函数中不鼓励(或甚至禁止?)副作用。

更好的方法是

之一
routeLists.stream()
    .flatMapToInt(innerList -> innerList.stream()
        .mapToInt(Route::getDistance))
    .sum()

routeLists.stream()
    .mapToInt(innerList -> innerList.stream()
        .mapToInt(Route::getDistance).sum())
    .sum()

对于每个子列表,第一个将创建一个距离流。所有这些流将变得扁平化并立即汇总。

第二个将创建每个子列表的总和,然后再将所有这些总和相加。

它们应该是等价的,但我不确定这个或那个在性能方面是否更好(即,如果压扁流比求和更昂贵)。

Andy Turner's answer涵盖了扁平化列表然后获取和总结距离的第三种方法。

答案 2 :(得分:0)

您不能将int用作变量,因为必须是最终的才能在流中使用。

但是你可以创建一个包装int的类。

然后声明保持此类为最终的变量。

更改内部int变量的内容。

public void findMax(List<List<Route>> routeLists) {
        final IntWrapper dWrapper = new IntWrapper();
        routeLists.forEach(e-> {
            e.forEach(ee -> {
                dWrapper.value += ee.getDistance();    
            });

        });

        int d = dWrapper.value;

        ... doing some other operation with d
    }

 public class IntWrapper {
    public int value;
 }