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
?
To add an illustration to Giovanni's answer, we can highlight the difference between
f::handle
andobj -> f.handle(obj)
if we replacef
with a method call:Output:
So, as you see
.forEach(f()::add)
will evaluatef()
right away and then calladd(...)
on the result as many times as the lambda is called.On the other hand,
str -> f().add(str)
will not do anything upfront but will call f() every time the lambda is invoked.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 thehandle
method. In the second case, at each call the JVM has to resolve thef
reference and it thus complains thatf
must befinal
. You could easily write code that setsf
tonull
while theforEach
is running and thus cause a NPE.