Consider following class:
class Foo<T> {
void handle(T t) {
System.out.println("handling " + t);
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
Foo<Integer> f = new Foo<>();
list.forEach(f::handle); // compiles fine
//list.forEach(obj -> f.handle(obj));// compilation error
f = new Foo<>(); // reassign f
}
}
Why do I get compilation error for obj -> f.handle(obj)
, but not for f::handle
?
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.
In Java 8, using lambda expression and Stream API we can pass processing logic of elements into methods provided by collections and now collection is responsible for parallel processing of elements and not the client. Also, parallel processing effectively utilizes multicore CPUs used nowadays.
A lambda expression can use a local variable in outer scopes only if they are effectively final.
Those are two different constructs that are doing two different things. In the first case, you are getting the method reference of a specific object: this needs to be done only once, after which the JVM has its own reference (so effectively final) to the object f
and can call the handle
method. In the second case, at each call the JVM has to resolve the f
reference and it thus complains that f
must be final
. You could easily write code that sets f
to null
while the forEach
is running and thus cause a NPE.
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