为什么在使用for-each时循环变量有效地最终化?

hua*_*gjs 5 java lambda final

  • 情况1:在使用for-each循环时可以工作吗?
    private void m10(String[] arr) {
        for (String s : arr) {
            Supplier<String> supplier = () -> {
                System.out.println(s);
                return null;
            };
            supplier.get();
        }
    }
Run Code Online (Sandbox Code Playgroud)

要么

    private void m10(Object[] arr) {
        for (Object s : arr) {
            Supplier<String> supplier = () -> {
                System.out.println(s);
                return null;
            };
            supplier.get();
        }
    }
Run Code Online (Sandbox Code Playgroud)
  • 情况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();
        }
    }
Run Code Online (Sandbox Code Playgroud)

在情况2中,我知道该变量i实际上不是最终变量,因为其值在循环迭代之间发生了变化。但是我不明白为什么lambda可以在情况1下工作。

Zab*_*uza 7

s永不更改(s = ...)。因此,编译器说“是的,理论上我们可以将其标记为final。那就是有效的final的意思。也就是说,您没有标记它,final但是您可以并且它仍然可以编译。

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

for (String s : arr)
Run Code Online (Sandbox Code Playgroud)

该变量不会超出的范围,for并且不会得到重新分配。即不是

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

该变量是在循环内部创建的,因此其范围仅限于循环。它不会重复使用,而是在每次迭代时都丢弃并重新创建:

for (int i = 0; i < arr.length; i++) {
    String s = arr[i];
    ...
}
Run Code Online (Sandbox Code Playgroud)

仔细看两个例子。首先,您无法编写代码final String s = null;,因为我们正在循环中重新分配它s = arr[i];。但是在第二个示例中我们可以,因为该变量s仅在一次迭代中已知,然后又被丢弃。所以final String s = arr[i];是好的。

作为附带说明,这也解释了为什么s循环后无法使用。它是未知的且已被破坏,其范围仅限于循环。