bad return type in lambda expression

51,224

Solution 1

If a lambda expression appears in a target type with wildcards (as in most cases)

  Consumer<? super Boolean> consumer = b->{...}

the question arises - what's the type of the lambda expression; in particular, the type of b.

Of course, there could be many choices due to the wildcards; e.g. we could explicitly choose

  Consumer<? super Boolean> consumer = (Object b)->{...}

However, implicitly, b should be inferred as Boolean. This makes sense since the consumer should only be fed with Boolean anyway.

http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.27.3

If T is a wildcard-parameterized functional interface type and the lambda expression is implicitly typed, then the ground target type is the non-wildcard parameterization of T

(This probably assumes that wildcards are use properly variance-wise on the target type; we might find some hilarious examples if the assumption doesn't hold)

Solution 2

<? super E> includes Object, which isn't a Boolean. ie

MyPredicate<? super E>

Could be a

MyPredicate<Object>

and you can't return an Object as a boolean.

Try changing your lambda to:

MyStream.<Boolean> create().filter(b -> Boolean.TRUE.equals(b));

which will compile and execute without error not matter the type of the stream, but will return true for elements that are true Boolean values.

Share:
51,224

Related videos on Youtube

Roland Illig
Author by

Roland Illig

Updated on October 13, 2020

Comments

  • Roland Illig
    Roland Illig over 3 years

    The following code compiles fine in IntelliJ and Eclipse, but the JDK compiler 1.8.0_25 complains. First, the code.

    import java.util.function.Predicate;
    
    public abstract class MyStream<E> {
    
      static <T> MyStream<T> create() {
        return null;
      }
    
      abstract MyStream<E> filter(MyPredicate<? super E> predicate);
    
      public interface MyPredicate<T> extends Predicate<T> {
    
        @Override
        boolean test(T t);
      }
    
      public void demo() {
        MyStream.<Boolean> create().filter(b -> b);
        MyStream.<String> create().filter(s -> s != null);
      }
    }
    

    The output from javac 1.8.0_25 is:

    MyStream.java:18: error: incompatible types: incompatible parameter types in lambda expression
        MyStream.<Boolean> create().filter(b -> b);
                                           ^
    MyStream.java:18: error: incompatible types: bad return type in lambda expression
        MyStream.<Boolean> create().filter(b -> b);
                                                ^
        ? super Boolean cannot be converted to boolean
    MyStream.java:19: error: bad operand types for binary operator '!='
        MyStream.<String> create().filter(s -> s != null);
                                                 ^
      first type:  ? super String
      second type: <null>
    MyStream.java:19: error: incompatible types: incompatible parameter types in lambda expression
        MyStream.<String> create().filter(s -> s != null);
                                          ^
    Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
    4 errors
    

    When I replace ? super E with simply E, JDK compiles successfully.

    When I replace filter(MyPredicate with filter(Predicate, JDK compiles successfully.

    Since it works with JDK 1.8.0_60, I suspect it is a compiler bug.

    Any details on what caused this and when it has been fixed?

    • ZhongYu
      ZhongYu over 8 years
      yes, I too believe it is a compiler bug. try workaround filter((Boolean b)->b))
  • ZhongYu
    ZhongYu over 8 years
    no - while the target type is Predicate<? super Boolean>, the type of the lambda expression should be Predicate<Boolean>. (jls#12.27.3). Therefore b has a static type of Boolean

Related