2015-10-12 19 views
7

Poniższy kod kompiluje dobrze w IntelliJ i Eclipse, ale kompilator JDK 1.8.0_25 narzeka. Najpierw kod.zły typ zwrotu w wyrażeniu lambda

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); 
    } 
} 

Wyjście z javac 1.8.0_25 jest:

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 

Kiedy wymienić ? super E ze po prostu E, JDK kompiluje pomyślnie.

Po zastąpieniu filter(MyPredicate przez filter(Predicate, JDK kompiluje się pomyślnie.

Ponieważ działa z JDK 1.8.0_60, podejrzewam, że jest to błąd kompilatora.

Jakieś szczegóły na temat tego, co spowodowało to i kiedy zostało naprawione?

+2

tak, ja też uważam, że jest to błąd kompilatora.spróbuj obejść 'filter ((Boolean b) -> b))' – ZhongYu

Odpowiedz

6

Jeśli wyrażenie lambda pojawia się w typ docelowy z symboli wieloznacznych (jak w większości przypadków)

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

powstaje pytanie - co to za typ wyrażenia lambda; w szczególności typu b.

Oczywiście może być wiele możliwości wyboru ze względu na symbole wieloznaczne; na przykład możemy jednoznacznie wybrać

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

jednak pośrednio, b należy wywnioskować jak Boolean. Ma to sens, ponieważ konsument powinien być zasilany tylko numerem Boolean.

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

Jeżeli T jest funkcjonalny typu interfejsu wieloznaczny-sparametryzowane i ekspresja lambda pośrednio maszynie, wówczas typ docelowego podłoża jest parametryzacja nie wieloznaczny T

(to prawdopodobnie zakłada, że ​​symbole wieloznaczne są odpowiednio wariancjonalne na typie docelowym, możemy znaleźć kilka zabawnych przykładów, jeśli założenie nie ma wartości)

1

, który nie jest Boolean. tj

MyPredicate<? super E> 

Może być

MyPredicate<Object> 

i nie można zwrócić Object jako boolean.

Spróbuj zmienić lambda:

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

które skompilować i wykonać bez błędu nie ma znaczenia rodzaj strumienia, ale powróci true dla elementów, które są trueBoolean wartości.

+3

no - podczas gdy typem docelowym jest 'Predicate ', typem wyrażenia lambda powinno być' Predicate '. (jls # 12.27.3). Dlatego 'b' ma statyczny typ' Boolean' – ZhongYu