【问题标题】:Why is the loop variable effectively final when using for-each? [duplicate]为什么在使用 for-each 时循环变量实际上是 final 的? [复制]
【发布时间】:2019-10-23 20:55:01
【问题描述】:
  • 案例一:使用for-each循环时可以工作:
    private void m10(String[] arr) {
        for (String s : arr) {
            Supplier<String> supplier = () -> {
                System.out.println(s);
                return null;
            };
            supplier.get();
        }
    }

    private void m10(Object[] arr) {
        for (Object s : arr) {
            Supplier<String> supplier = () -> {
                System.out.println(s);
                return null;
            };
            supplier.get();
        }
    }
  • 案例 2:它会捕获编译时错误
    private void m11(String[] arr) {
        for (int i = 0; i < arr.length; i++) {
            Supplier<String> supplier = () -> {
                System.out.println(arr[i]);
                return null;
            };
            supplier.get();
        }
    }

在情况 2 中,我知道变量 i 不是有效的最终变量,因为它的值在循环迭代之间发生了变化。但我不明白为什么 lambda 可以在案例 1 中工作。

【问题讨论】:

  • 了解s 的作用域会有所帮助:How is Java's for loop code generated by the compiler
  • 因为for(final String s : arr) 也是有效的。这就是有效地最终的意思;添加 final 关键字不会破坏它。
  • 您可以认为案例 1 等同于在案例 2 的循环中执行 String s = arr[i]; 的第一件事。这也将允许您在 lambda 中执行 System.out.println(s);,因为 s 实际上是最终的. (感谢@Slaw 指出这是重复的;原始问题中有更多信息。)

标签: java lambda final


【解决方案1】:

s 永远不会改变 (s = ...)。所以编译器会说“是的,理论上我们可以将其标记为final。这就是有效最终的意思。 IE。你没有标记它final,但你可以并且它仍然会编译。

如果您想了解增强的 for 循环:

for (String s : arr)

变量不在for 的范围之外,也不会被重新分配。 IE。它是不是

String s = null;
for (int i = 0; i < arr.length; i++) {
    s = arr[i];
    ...
}

变量是在循环内部创建的,所以它的作用域仅限于循环。它不会被重复使用,而是被丢弃并在每次迭代时重新创建:

for (int i = 0; i < arr.length; i++) {
    String s = arr[i];
    ...
}

仔细看看这两个例子。首先,您不能写final String s = null;,因为我们在循环s = arr[i]; 期间重新分配它。但在第二个例子中我们可以,因为变量s 仅在一次迭代中已知,然后再次被丢弃。所以final String s = arr[i]; 很好。

作为旁注,这也解释了为什么你不能在循环后使用s。它是未知的并且已经被销毁,它的范围仅限于循环。

【讨论】:

    【解决方案2】:

    因为s 的范围是单次迭代,所以没有一个s 会改变值,但每次循环迭代都有一个有效的最终s

    这就像用以下方式编写你的案例 2,它确实可以编译

    private void m11(String[] arr) {
        for (int i = 0; i < arr.length; i++) {
            String s = arr[i];
            Supplier<String> supplier = () -> {
                System.out.println(s);
                return null;
            };
            supplier.get();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-08-03
      • 1970-01-01
      • 1970-01-01
      • 2010-10-17
      • 2017-02-11
      • 2021-10-01
      • 1970-01-01
      • 2020-12-24
      • 1970-01-01
      相关资源
      最近更新 更多