Why does .forEach(val -> list.add()) compile whereas .forEach(val -> true) doesn't? [duplicate]

  • A+
Category:Languages

It's better to express this behavior in the code:

List<Integer> list= new ArrayList<>(); Stream.of(1,2,3).forEach(i -> list.add(1));  // COMPILES  Stream.of(1,2,3).forEach(i -> true);  // DOES NOT COMPILE! 

forEach(...) accepts Consumer, but why does the first example compile if List interface has following signature boolean add(E e)? whereas the second yields:

bad return type in lambda expression: boolean cannot be converted to void

 


Though you might be looking just for

Stream.of(1,2,3).forEach(list::add); // adding all to `list` 

why does the first example compile if List interface has following signature boolean add(E e)

Primarily because the return type of the method is ignored in the first call. This is what it expands to:

Stream.of(1,2,3).forEach(new Consumer<Integer>() {     @Override     public void accept(Integer i) {         list.add(1); // ignored return type     } });  // COMPILES 

On the other hand, the other lambda representation is more like a Predicate(which is also a FunctionalInterface) represented as returning true always from its test method. If you even try to represent it as a Consumer, it might just look like

Stream.of(1,2,3).forEach(new Consumer<Integer>() {     @Override     public void accept(Integer i) {         return true; // you can correlate easily now why this wouldn't compile      } });  // DOES NOT COMPILE! 

To add to the design basis via a comment from Brian

Java allows you to call a method and ignore the return value (a method invocation expression as a statement). Since we allow this at the invocation, we also allow this when adapting a method to a functional interface whose arguments are compatible but the functional interface is void-returning.

Edit: To put it in his own words as close to the language spec:

More precisely, list.add(x) is a statement expression, and therefore is void-compatible. true is not a statement expression, and therefore not void-compatible. forEach(Consumer) requires a void-compatible lambda.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: