Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 634
Leonid Dashko Avatar asked Dec 15 '18 15:12

Leonid Dashko


1 Answers

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.

like image 137
Naman Avatar answered Oct 21 '22 05:10

Naman