Uwaga: Znalazłem wiele pytań wskazujących różnice między javac
i kompilatorem Eclipse, ale o ile mogłem zobaczyć, wszystkie z nich omawiają inne problemy.Generics i lambdas - różne zachowania w javacu i kompilatorze Eclipse
Załóżmy, że mamy tę metodę:
public static <T, U> void foo(Supplier<T> a, Function<T, U> b, Consumer<U> c)
{
c.accept(b.apply(a.get()));
}
znalazłem różne zachowanie między javac
i kompilator Eclipse Java przy zestawianiu połączeń do tej metody i nie jestem pewien, który z nich ma rację.
proste zastosowanie tej metody może być:
// variant 1
foo(
() -> Optional.of("foo"),
value -> value.get(),
value -> System.out.println(value));
Kompilator powinny być zdolne do wiązania T
do Optional<String>
pomocą pierwszego argumentu i U
do String
pomocą drugiego. Więc to wezwanie powinno być ważne (moim zdaniem).
To kompiluje grzywny za pomocą javac
ale nie kompilacji przy użyciu Eclipse:
Niezgodność typów: nie można przekonwertować z pustki do <nieznanego>
Dodanie typu argumentu pierwszego argumentu (() -> Optional.<String> of("foo")
) sprawia, że kompiluje się również w Eclipse.
Pytanie: Z punktu widzenia specyfikacji, czy Eclipse jest prawidłowy w odrzucaniu tego połączenia (i dlaczego (nie))?
Załóżmy teraz chcemy rzucać niestandardowy (wykonywania) wyjątek, jeśli Optional
jest pusty:
// variant 2
foo(
() -> Optional.of("foo"),
value -> value.orElseThrow(() -> new RuntimeException()),
value -> System.out.println(value));
ten zostaje odrzucony zarówno przez javac
i kompilator Eclipse, ale z różnych komunikatów o błędach :
javac
„nieudokumentowanych wyjątkiem X, musi być złapany lub uznane za wyrzucane”- Eclipse kompilator: „Niezgodność typów: nie można przekonwertować z pustki do <nieznany>”
Kiedy dodać typ argumentu pierwszego argumentu, jak wyżej, Eclipse uda się kompilacja natomiast javac
nadal kończy się niepowodzeniem. Kiedy dodaję <RuntimeException>
jako typ argumentu do drugiego argumentu, jest odwrotnie, Eclipse nie powiedzie się i javac
się powiedzie.
Pytanie: Znowu, czy kompilatory mają rację, odrzucając to połączenie i dlaczego?
Moim zdaniem oba warianty powinny kompilować dobrze bez dodatkowych wskazówek przy użyciu argumentów typu. Jeśli tak, wypełnię jeden raport o błędzie dla javac
(dotyczący "niezgłoszonego wyjątku") i jeden dla kompilatora Eclipse (dotyczący "niezgodności typów"). Ale najpierw chcę mieć pewność, że specyfikacja podziela mój punkt widzenia.
wersje stosowane:
javac
: 1.8.0_66- Eclipse JDT: 3.11.1.v20151118-1100
Edycja:
Napełniłem bug 482781 dla problemu w Eclipse.
Problem z numerem javac
jest już zgłoszony jako JDK-8056983, patrz Tunakis answer.
Obwiniam zaćmienie w razie wątpliwości :) Wnioskowanie jest bardzo skomplikowane, cała składnia lambda jest wciąż całkiem nowa. Eclipse ma kilka błędów naprawionych, ale niektóre pozostały w obecnej wersji, związane z takimi przypadkami. – zapl
Kompilator Eclipse Mars ECJ jest bardzo wadliwy w porównaniu do najnowszej wersji Luny, jeśli chodzi o ogólną ekspansję. Już potknąłem się o co najmniej trzy przypadki, gdy ECJ 3.11 zawiedzie lub nawet utknął w nieskończonej pętli, podczas gdy javac i ECJ 3.10 poprawnie się kompilują. Dlatego wciąż używam Luny. –
Błąd Eclipse został już naprawiony na 4.6 M1 przez https://bugs.eclipse.org/470826, który jest również zaplanowany na port z powrotem na mars.2. –