【问题标题】:java 8 local variable in stream.foreach [duplicate]stream.foreach中的java 8局部变量[重复]
【发布时间】:2018-03-14 08:46:30
【问题描述】:

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

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

【问题讨论】:

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


【解决方案1】:

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+,你可能需要添加 routeLists.Strem()
  • @Niraj 是的。我没有特别注意类型。实际上,也需要flatMap。感谢您强调。
  • @Eugene 已修复..
【解决方案2】:

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

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

然后将持有这个类的变量声明为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;
 }

【讨论】:

  • 感谢大家,主要是感谢您。
【解决方案3】:

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

更好的方法是

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 涵盖了扁平化列表然后获取和求和距离的第三种选择。

【讨论】:

    猜你喜欢
    • 2012-08-03
    • 2018-04-18
    • 1970-01-01
    • 2013-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-10
    • 1970-01-01
    相关资源
    最近更新 更多