Hinweis: Ich habe mehrere Fragen gefunden, die Unterschiede zwischen javac
und dem Eclipse-Compiler zeigen, aber soweit ich sehen konnte, diskutieren alle anderen Probleme.Generics und Lambdas - unterschiedliches Verhalten in Javac und Eclipse Compiler
Angenommen, wir haben diese Methode:
public static <T, U> void foo(Supplier<T> a, Function<T, U> b, Consumer<U> c)
{
c.accept(b.apply(a.get()));
}
ich unterschiedliches Verhalten zwischen javac
und die Eclipse-Java-Compiler gefunden, wenn Anrufe an diese Methode kompilieren und ich bin mir nicht sicher, wer von beiden recht hat.
Eine einfache Anwendung dieses Verfahrens könnte sein:
// variant 1
foo(
() -> Optional.of("foo"),
value -> value.get(),
value -> System.out.println(value));
Der Compiler der Lage sein sollte zu T
Optional<String>
unter Verwendung des ersten Arguments und U
zu String
unter Verwendung des zweiten zu binden. Also sollte dieser Anruf (meiner Meinung nach) gültig sein.
Dies kompiliert feinen javac
verwenden, aber nicht Eclipse kompilieren mit:
Typenkonflikt: kann nicht von Leere konvertieren <unbekannt>
eine Art Argument auf das erste Argument Hinzufügen (() -> Optional.<String> of("foo")
) macht es auch in Eclipse kompilieren.
Frage: Aus Sicht der Spezifikation ist Eclipse korrekt in der Ablehnung dieses Aufrufs (und warum (nicht))?
Jetzt nehmen wir eine benutzerdefinierte (Runtime) Ausnahme werfen wollen, wenn die Optional
leer ist:
// variant 2
foo(
() -> Optional.of("foo"),
value -> value.orElseThrow(() -> new RuntimeException()),
value -> System.out.println(value));
Dies wird durch beide abgelehnt, javac
und der Eclipse-Compiler, aber mit verschiedenen Fehlermeldungen
javac
: "nicht gemeldete Ausnahme X, müssen gefangen oder deklariert werden geworfen werden"- Eclipse-Compiler:
: „Typenkonflikt kann nicht von Leere zu <unbekannt> konvertieren“ Wenn ich den Typ Argument auf das erste Argument hinzufügen, wie oben Eclipse erfolgreich bei der Erstellung während javac
immer noch nicht. Wenn ich <RuntimeException>
als Typargument zu dem zweiten Argument hinzufüge, ist es umgekehrt, Eclipse schlägt fehl und javac
ist erfolgreich.
Frage: Noch einmal, haben die Compiler Recht, diesen Aufruf abzulehnen und warum?
Meiner Meinung nach sollten beide Varianten gut ohne zusätzliche Hinweise kompilieren, indem Sie type Argumente verwenden. Wenn das der Fall ist, fülle ich einen Fehlerbericht für javac
(in Bezug auf die "nicht gemeldete Ausnahme") und einen für den Eclipse-Compiler (in Bezug auf den "Typenkonflikt"). Aber zuerst möchte ich sicher sein, dass die Spezifikation meine Sichtweise teilt.
verwendet Versionen:
javac
: 1.8.0_66- Eclipse-JDT: 3.11.1.v20151118-1100
EDIT:
I gefüllt bug 482781 für das Problem in Eclipse. Das Problem mit javac
ist bereits gemeldet als JDK-8056983, siehe Tunakis answer.
Wäre Schuld im Zweifel Eklipse :) Typ Inferenz ist sehr kompliziert, die ganze Lambda-Syntax ist noch ziemlich neu. Eclipse hat einige Bugs behoben, aber einige sind in der aktuellen Version übrig geblieben. – zapl
Der Eclipse Mars ECJ Compiler ist im Vergleich zum neuesten Luna wirklich buggy, wenn es um generische Erweiterungen geht. Ich bin schon mit mindestens drei Fällen gestolpert, als ECJ 3.11 fehlschlägt oder sogar in der Endlosschleife feststeckt, während javac und ECJ 3.10 richtig kompilieren. Deshalb benutze ich immer noch Luna. –
Der Eclipse-Fehler wurde bereits für 4.6 M1 über https://bugs.eclipse.org/470826 behoben, der auch für den Backport auf mars.2 vorgesehen ist. –