Я разработал некоторый код в Eclipse, успешно проверил его, отправил на наш сервер Jenkins CI и получил электронное письмо, которое Maven задыхался из-за ошибки компиляции Java. Впоследствии я выделил проблему и создал следующий минимальный пример, показывающий проблему:
import java.util.List;
import java.util.function.Function;
class MinimalTypeFailureExample {
public static void main(String[] args) {
List<String> originalList = null; // irrelevant
List<IntToByteFunction> resultList = transform(originalList,
outer -> inner -> doStuff(inner, outer));
System.out.println(resultList);
}
static <F, T> List<T> transform(List<F> originalList,
MyFunction<? super F, ? extends T> function) {
return null; // irrelevant
}
static Byte doStuff(Integer inner, String outer) {
return null; // irrelevant
}
}
@FunctionalInterface
interface MyFunction<F, T> extends Function<F, T> {
@Override
T apply(F input);
}
@FunctionalInterface
interface IntToByteFunction {
Byte applyIntToByte(Integer inner);
}
В Eclipse этот код компилируется без ошибок и, кажется, выполняется как задумано. Однако компиляция с использованием javac выдает следующую ошибку:
MinimalTypeFailureExample.java:7: error: incompatible types: cannot infer type-variable(s) F,T
List<IntToByteFunction> resultList = transform(originalList, outer -> inner -> doStuff(inner, outer));
^
(argument mismatch; bad return type in lambda expression
T is not a functional interface)
where F,T are type-variables:
F extends Object declared in method <F,T>transform(List<F>,MyFunction<F,? extends T>)
T extends Object declared in method <F,T>transform(List<F>,MyFunction<F,? extends T>)
1 error
Изменение типа аргумента transform()
с MyFunction
на Function
или удаление подстановочного знака ? extends
в типе аргумента приводит к компиляции примера кода в javac.
Очевидно, что Eclipse или javac нарушают Спецификацию языка Java. Вопрос в том, подать ли отчет об ошибке в Eclipse или javac ? Правила вывода типов для универсальных лямбд настолько сложны, что я понятия не имею, является ли эта программа допустимой Java или нет в соответствии с JLS.
Мотивация
В исходном коде transform()
был com.google.common.collect.Lists.transform()
Гуавы. Интерфейс MyFunction
был интерфейсом com.google.common.base.Function
компании Guava, который по историческим причинам расширяет java.util.function.Function
.
Целью этого кода было создание представления списка первого типа в виде списка второго типа. Второй тип был функциональным интерфейсным типом, и я хотел заполнить выходной список функциями этого типа, построенными на основе значений в входном списке - отсюда и карманное лямбда-выражение.
Информация о версии для воспроизводимости
Проверенные версии Eclipse:
- 2018-09 (4.9.0) Идентификатор сборки: 20180917-1800
- 2019-03 RC1 (4.11 RC1) Идентификатор сборки: 20190307-2044
протестированные версии javac: