private void m10(String[] arr) {
for (String s : arr) {
Supplier<String> supplier = () -> {
System.out.println(s);
return null;
};
supplier.get();
}
}
or
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();
}
}
In case 2, I know the variable i
is not effectively final because its value changed between loop iterations. But I cannot understand why the lambda can work in case 1.
Forcing the variable to be final avoids giving the impression that incrementing start inside the lambda could actually modify the start method parameter.
The local variables that a lambda expression may use are referred to as “effectively final”. An effectively final variable is one whose value doesn't change after it's first assigned. There is no need to explicitly declare such a variable as final, although doing so would not be an error.
4 states that if we remove the final modifier from a method parameter or a local variable without introducing compile-time errors, then it's effectively final. Moreover, if we add the final keyword to a variable's declaration in a valid program, then it's effectively final.
Final variables can be used to construct trees of immutable objects. Once constructed, these objects are guaranteed not to change anymore. To achieve this, an immutable class must only have final fields, and these final fields may only have immutable types themselves.
s
is never changed (s = ...
). So the compiler says "yeah, we could theoretically mark this as final
". That is what is meant by effectively final. I.e. you did not mark it final
but you could and it would still compile.
In case you are wondering about the enhanced for-loop:
for (String s : arr)
The variable does not live outside of the scope of the for
and does not get re-assigned. I.e. it is not:
String s = null;
for (int i = 0; i < arr.length; i++) {
s = arr[i];
...
}
The variable is created inside the loop, so its scope is limited to the loop. It is not re-used but thrown away and re-created each iteration:
for (int i = 0; i < arr.length; i++) {
String s = arr[i];
...
}
Take a close look at the two examples. In the first, you could not write final String s = null;
, because we are re-assigning it during the loop s = arr[i];
. But in the second example we can, because the variable s
is only known within one iteration and then thrown away again. So final String s = arr[i];
is fine.
As a side note, this also explains why you can not use s
after the loop. It is unknown and destroyed already, its scope is limited to the loop.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With