此问题已经在这里有了答案:
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();
}
}
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
从不更改(s = ...
)。因此,编译器说“是的,理论上我们可以将其标记为final
”。这就是有效最终的意思。即您没有将其标记为final
,但可以并且仍会编译。
如果您想了解增强的for循环:
for (String s : arr)
该变量不会超出for
的范围,也不会被重新分配。即它是not:
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
。它是未知的并且已经被销毁,其范围仅限于循环。
因为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();
}
}