【问题标题】:Using the non final loop variable inside a lambda expression在 lambda 表达式中使用非最终循环变量
【发布时间】:2015-12-08 14:44:35
【问题描述】:

我正在尝试通过 executors 和 runnable 并行执行 100 个任务,该任务需要使用循环变量:

for (int i = 0; i < 100; i++) {
   executor.execute(() -> {
     doSomething(String.format("Need task number %d done", i));
   }
  });
}

我在“我”下面有一个波浪线 - Variable used in lambda expression should be effectively final.

据我所知,循环变量不能成为最终变量或有效最终变量,因为每次迭代都会更改它。我找到了一个简单的解决方法,

for (int i = 0; i < 100; i++) {
   int index = i;
   executor.execute(() -> {
     doSomething(String.format("Need task number %d done", index));
   }
 });
}

这对我来说似乎不是最有效的解决方案,每次迭代都声明一个新变量。有更好的方法吗?

【问题讨论】:

  • 这是局部变量,所以我认为这并不重要
  • @ka4eli - 同意。性能方面没关系。 JVM 很可能会直接删除它并直接使用i。为了程序员,有效最终要求仅由 javac 强制执行。运行时只是捕获当前值。
  • @bayou.io 很有意思,没想到JVM优化。
  • 我刚遇到同样的问题,使用了同样的解决方案。:) 那么为什么在 lambda 表达式中可以看到 index 而在循环计数器中看不到呢?

标签: java lambda final executorservice


【解决方案1】:

将 lambda 表达式代码包装到方法中并将该方法调用到循环中,这种方式是标准的 lambda 表达式可维护代码

for(int i=1;i<=6;i++){  doSomeThing(i); }


static void doSomeThing(int i)
    { Thread loop=new Thread(()->{print(i);}); // jvm point of view is final
        loop.setPriority(Thread.MIN_PRIORITY);
        loop.start();
    }

【讨论】:

    【解决方案2】:

    有更好的方法吗?

    我对此表示怀疑。您的解决方案对我来说看起来不错,但是如果您愿意,可以将其重写为可能更清晰的代码,例如:

    IntStream.range(0, 100).forEach(
        i -> executor.execute(
            () -> doSomething(String.format("Need task number %d done", i))
        )
    );
    

    【讨论】:

    • 这是简洁而优秀的。我会用它。非常感谢。
    【解决方案3】:

    这是让它发挥作用的最直接的方法。你不会做得比这更好。

    【讨论】:

    • 同意。除非我们有一个实用程序 Iterable&lt;Integer&gt; - for(int i: range(0, 100)) - 这里 i 将是有效的最终结果。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-19
    • 1970-01-01
    • 2014-08-15
    • 1970-01-01
    • 1970-01-01
    • 2010-10-20
    相关资源
    最近更新 更多