Reputation: 1812
Consider the following lines of codes.
Object object = "s";
Optional.empty().ifPresent(s -> ((StringBuffer) object).append(s));
Optional.empty().ifPresent(((StringBuffer) object)::append);
Functionally, line 2 and line 3 are the same. In fact, in IntelliJ, it suggests that I use method reference for line 2, which would then be exactly the same as line 3. However, when I run the codes with Java 8, line 2 executes fine but line 3 throws a ClassCastException. Obviously, the exception will happen if the codes in ifPresent() are executed, but in both lines 2 and 3, the codes in ifPresent() should not even be executed. So how do we explain the exception happening in line 3?
Upvotes: 1
Views: 308
Reputation: 140318
These two aren't the same (and it's a bug in intellij if it suggests this refactoring, at least without explicitly stating the caveat that they have different semantics).
Optional.empty().ifPresent(s -> ((StringBuffer) object).append(s));
Here, the cast is evaluated when the Consumer
is executed. It is effectively:
Optional.empty().ifPresent(new Consumer<Object>() {
@Override public void accept(Object s) {
((StringBuffer) object).append(s);
}
});
so this will only throw ClassCastException
if the consumer is invoked.
OTOH
Optional.empty().ifPresent(((StringBuffer) object)::append);
is effectively:
Optional<Object> empty = Optional.empty();
StringBuffer sb = (StringBuffer) object;
empty.ifPresent(new Consumer<Object>() {
@Override public void accept(Object s) {
sb.append(s);
}
});
Hence, this will throw a ClassCastException
before the consumer is invoked.
Upvotes: 1