java stream.foreach 中的 8 个局部变量

java 8 local variable in stream.foreach

我想在 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
    }
}

如何在不将它们设置为全局变量的情况下使用它们?

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

但是您可以创建一个 class 包装 int。

然后将持有这个class的变量声明为final。

正在更改内部 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;
 }

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();
  }
}

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

更好的方法是

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

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

第一个将为每个子列表创建一个距离流。所有这些流将变得扁平化并立即求和。

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

它们应该是等效的,但我不确定两者在性能方面是否更好(即,如果展平流比求和更昂贵)。

.

涵盖了展平列表然后获取和求和距离的第三种选择。