Warum tut dieses Java 8 lambda nicht kompilieren?
Den folgenden Java-code compilieren zu:
@FunctionalInterface
private interface BiConsumer<A, B> {
void accept(A a, B b);
}
private static void takeBiConsumer(BiConsumer<String, String> bc) { }
public static void main(String[] args) {
takeBiConsumer((String s1, String s2) -> new String("hi")); //OK
takeBiConsumer((String s1, String s2) -> "hi"); //Error
}
Meldet der compiler:
Error:(31, 58) java: incompatible types: bad return type in lambda expression
java.lang.String cannot be converted to void
Komisch ist, dass die Zeile "OK" kompiliert in Ordnung, aber die Zeile "Error" fehl. Sie scheinen im wesentlichen identisch.
ist es ein Tippfehler, dass hier die funktionale interface-Methode void zurückgibt?
NÖ. Es stellt sich heraus, dass im Mittelpunkt der Frage - siehe die akzeptierte Antwort.
sollte es code innerhalb der
Schnittstellen mit einer einzigen Methode sind austauschbar mit Lambda-Ausdrücke in Java 8. In diesem Fall
NÖ. Es stellt sich heraus, dass im Mittelpunkt der Frage - siehe die akzeptierte Antwort.
sollte es code innerhalb der
{ }
von takeBiConsumer
... und wenn ja, könnten Sie ein Beispiel geben ... wenn ich das richtig gelesen, bc
ist eine Instanz der Klasse/Schnittstelle BiConsumer
, und so sollte eine Methode namens accept
entsprechen die interface-Signatur ... ... und wenn das richtig ist, dann sind die accept
Methode muss irgendwo definiert sein (z.B. eine Klasse, die die Schnittstelle implementiert) ... so ist das, was sollte in der {}
?? ... ... ... dankeSchnittstellen mit einer einzigen Methode sind austauschbar mit Lambda-Ausdrücke in Java 8. In diesem Fall
(String s1, String s2) -> "hi"
ist eine Instanz von BiConsumer<String,String>.InformationsquelleAutor Brian Gordon | 2015-03-25
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ihren lambda muss deckungsgleich sein mit
BiConsumer<String, String>
. Wenn Sie beziehen sich auf JLS #15.27.3 (Typ Lambda):Also den lambda-Ausdruck muss entweder ein Ausdruck oder eine Anweisung void kompatibel block:
InformationsquelleAutor assylias
Im Grunde,
new String("hi")
ist ein ausführbares Stück code, der tatsächlich etwas tut (es erstellt eine neue Zeichenfolge, und dann gibt es zurück). Der Rückgabewert kann ignoriert werden undnew String("hi")
kann noch immer verwendet werden void-return lambda-Ausdruck zum erstellen einer neuen Zeichenfolge.Jedoch
"hi"
ist einfach eine Konstante, die nicht tun, alles auf eigene. Die einzige vernünftige Sache zu tun, die in lambda-Körper ist zurück. Aber die lambda-Methode haben return-TypString
oderObject
, aber es gibtvoid
, damit dieString cannot be casted to void
Fehler.String
literal ist nur ein expression kann nicht verwendet werden, in einem - Anweisung in context.Die akzeptierte Antwort ist formal richtig, aber das ist eine bessere Erklärung
das ist, warum diese Antwort kam von Ihnen positiv bewertet werden, wie gut. Die Begründung für die Regeln und die nicht-formale intuitive Erklärung könnte in der Tat helfen, aber jeder Programmierer sollte sich bewusst sein, dass es formale Regeln, die dahinter steht und in dem Fall, dass die formale Regel das Ergebnis ist nicht intuitiv verständlich, die formale Regel noch gewinnt. E. g.
()->x++
legal ist, während()->(x++)
im Grunde genau das tut, ist nicht...InformationsquelleAutor kajacx
Ersten Fall ok ist, weil Sie den Aufruf einer "speziellen" Methode (ein Konstruktor) und Sie sind nicht eigentlich unter das erstellte Objekt. Nur um es noch klarer, werde ich die optionalen Verstrebungen in Ihrem lambdas:
Und mehr klar, ich werde übersetzen, dass der ältere Schreibweise:
Im ersten Fall werden Sie bei der Ausführung eines Konstruktors, aber Sie sind NICHT Rückgabe des erzeugten Objekts, im zweiten Fall müssen Sie versuchen, einen String-Wert, aber Ihre Methode in der Schnittstelle
BiConsumer
gibt void zurück, daher die compiler-Fehler.InformationsquelleAutor morgano
Den JLS angeben, dass
Lassen Sie uns nun sehen, dass im detail,
Seit Ihr
takeBiConsumer
Methode ist vom Typ void, die lambda-Empfangnew String("hi")
interpretiert wird es als ein block wiedie gültig ist in eine Lücke, damit der erste Fall kompilieren.
Jedoch in dem Fall, in dem der lambda-Ausdruck
-> "hi"
, einen block wieist keine gültige syntax in java. Also das einzige, was zu tun mit "hi" ist, zu versuchen, es zurückzugeben.
ist nicht gültig in einer leere und erklären Sie die Fehlermeldung
Für ein besseres Verständnis, beachten Sie, dass wenn Sie ändern die Art der
takeBiConsumer
in einen String-> "hi"
gültig sein wird, da es einfach versuchen, direkt den string.Beachten Sie, dass ich zuerst dache der Fehler wurde verursacht durch den lambda-Ausdruck in eine falsche Aufruf-Kontext, so werde ich zu teilen, diese Möglichkeit mit der community :
JLS 15.27
Jedoch in unserem Fall, wir sind in einer invocation-context korrekt ist.
InformationsquelleAutor Jean-François Savard