2015-11-21 4 views
7

Примечание: Я нашел несколько вопросов, указывающих различия между javac и компилятором Eclipse, но насколько я мог видеть, все они обсуждают другие проблемы.Generics и lambdas - различное поведение в javac и компиляторе Eclipse

Предположим, у нас есть этот метод:

public static <T, U> void foo(Supplier<T> a, Function<T, U> b, Consumer<U> c) 
{ 
    c.accept(b.apply(a.get())); 
} 

я нашел различное поведение между javac и компилятор Eclipse, Java при компиляции вызовов этого метода, и я не уверен, какой из этих двух прав.


Простое использование этого метода может быть:

// variant 1 
foo(
    () -> Optional.of("foo"), 
    value -> value.get(), 
    value -> System.out.println(value)); 

Компилятор должен быть способен связываться с TOptional<String>, используя первый аргумент и U к String с помощью второй. Поэтому этот звонок должен быть действительным (на мой взгляд).

Это нормально компилируется с помощью javac, но не для компиляции с помощью Eclipse:

Несоответствие типа: не удается преобразовать из пустоты в < неизвестной >

Добавление аргумент типа первого аргумента (() -> Optional.<String> of("foo")) делает его компиляцией в Eclipse тоже.

Вопрос: С точки зрения спецификации Eclipse правильно отклоняет этот вызов (и почему (не))?


Теперь предположим, что мы хотим, чтобы бросить пользовательский (выполнения) исключение, если Optional пуст:

// variant 2 
foo(
    () -> Optional.of("foo"), 
    value -> value.orElseThrow(() -> new RuntimeException()), 
    value -> System.out.println(value)); 

Это отвергается как, javac и компилятор Eclipse,, но с различными сообщениями об ошибках :

  • javac: "незарегистрированные исключением X, должны быть пойманы или объявленный быть выброшен"
  • Eclipse, компилятор: «Несоответствие типов: невозможно преобразовать из пустоты в < неизвестно >»

Когда я добавить аргумент типа к первому аргументу, как указано выше, Eclipse преуспевает в компиляции, а javac до сих пор не удается. Когда я добавляю <RuntimeException> как аргумент типа ко второму аргументу, это наоборот, Eclipse терпит неудачу и javac преуспевает.

Вопрос: Опять же, компиляторы правильно отклоняют этот вызов и почему?


По моему мнению оба варианта должны компилироваться без дополнительных подсказок с использованием аргументов типа. Если это так, я заполню один отчет об ошибке для javac (относительно «незарегистрированного исключения») и один для компилятора Eclipse (относительно «несоответствия типа»). Но сначала я хочу быть уверенным, что спецификация разделяет мою точку зрения.

Версии, используемые:

  • javac: 1.8.0_66
  • Eclipse, JDT: 3.11.1.v20151118-1100

EDIT:

Я заполнил bug 482781 для выпуска в Eclipse.

Вопрос с javac уже представлен как JDK-8056983, см. Tunakis answer.

+1

Заблудился бы затмение, если у вас возникли сомнения. Тип вывода очень сложный, весь синтаксис лямбда все еще совершенно новый. У Eclipse исправлено несколько ошибок, но некоторые остались в текущей версии, связанные с такими крайними случаями. – zapl

+1

Eclipse Mars ECJ компилятор действительно багги по сравнению с последней Luna, когда речь заходит об общем расширении. Я уже столкнулся с по меньшей мере тремя случаями, когда ECJ 3.11 терпит неудачу или даже застревает в бесконечном цикле, в то время как javac и ECJ 3.10 скомпилированы правильно. Вот почему я все еще использую Луну. –

+0

Ошибка Eclipse уже исправлена ​​для 4.6 M1 через https://bugs.eclipse.org/470826, которая также запланирована для обратного порта на марс. 2 –

ответ

5

Да, вы правы во всех аспектах. Я, честно говоря, не смогу ссылаться на конкретные строки JLS об этом: введите вывод is a whole chapter.

Отказ от ответственности: Я тестировал использование Eclipse Mars 4.5.1 и JDK 1.8.0_60.


Вариант 1 должен скомпилировать и Eclipse, есть ошибка здесь. Я не мог найти ничего связанного с этим в их Bugzilla, чтобы вы могли пойти и подать его. Вы можете убедиться, что он должен составить, если вы уменьшаете свой пример этому:

public static <T> void foo(Supplier<T> a) { 
    a.get(); 
} 

foo(() -> Optional.of("foo")); 

Это отлично компилируется как с Eclipse, и javac. Добавление параметров делает (должно) не изменять тип, выводимый для T во время компиляции.


Вариант 2 не компилируется javac и это действительно ошибка, как сообщалось в JDK-8056983. Компилятор должен уметь заключить, что X - RuntimeException. Что касается того, почему Eclipse все еще не в состоянии скомпилировать это, опять-таки, я не смог найти ничего в их Bugzilla, поэтому не стесняйтесь сообщать об этом!

+1

Исправление для https://bugs.eclipse.org/470826 позволяет Eclipse принимать оба варианта. –

Смежные вопросы