it-swarm.com.ru

Целевой тип этого выражения должен быть функциональным интерфейсом.

Я создал функцию для фильтрации с несколькими предикатами, для которых я выполняю логическое И для них:

@SafeVarargs
public static <T> Stream<T> filter(Stream<T> source, Predicate<T>... predicates) {
    return source.filter(Arrays.stream(predicates).reduce(predicates[0], Predicate::and));
}  

При звонке:

filter(IntStream.range(0, 10).boxed(), x -> x % 2 != 0, x -> x%3 == 0).forEach(System.out::println);

Он работает нормально и печатает 3 и 9. Однако, когда я передаю один предикат, такой как:

filter(IntStream.range(0, 10).boxed(), x -> x % 2 != 0).forEach(System.out::println);

Я получаю ошибку компиляции:

The target type of this expression must be a functional interface

Почему это?

enter image description here Для информации я использую Eclipse Luna версии 1.

14
user2336315

Это угловой случай для компилятора. Чтобы определить, следует ли применять обтекание аргументов varargs в массиве или просто передать массив, ему необходимо знать тип последнего аргумента, однако в случае лямбда-выражения ему требуется сигнатура вызываемого метода для определения тип. Но ясно, что должно произойти, поскольку лямбда-выражение никогда не может быть типом массива, и поэтому javac компилирует его без проблем.

Одним приемлемым обходным решением будет перегрузка метода:

@SafeVarargs
public static <T> Stream<T> filter(Stream<T> source, Predicate<T>... predicates) {
    return source.filter(
        Arrays.stream(predicates).reduce(predicates[0], Predicate::and));
}
public static <T> Stream<T> filter(Stream<T> source, Predicate<T> predicate) {
    return source.filter(predicate);
}

Это был бы приемлемый обходной путь, поскольку он не требует каких-либо изменений на вызывающей стороне, одновременно повышая эффективность для случая единственного аргумента.


Пожалуйста, обратите внимание, что ваш метод varargs допускает нулевые аргументы, но потерпит неудачу при вызове таким способом. Так что вы должны либо добавить еще одну перегрузку:

public static <T> Stream<T> filter(Stream<T> source) {
    return source;
}

или сделайте метод безопасным для случая с нулевым аргументом:

@SafeVarargs
public static <T> Stream<T> filter(Stream<T> source, Predicate<T>... predicates) {
    return Arrays.stream(predicates).reduce(Predicate::and)
                 .map(source::filter).orElse(source);
}
8
Holger

И Netbeans, и Eclipse имеют ряд ошибок в области синтаксического анализа лямбда-выражений в Java. Они постепенно исправляются, но до тех пор, пока они не найдутся, я нашел лучшие обходные пути: 1. объявлять типы 2. если это не сработает, используйте блок 3. если это не работает, создайте анонимный объект, который реализует предикат/функцию и т. д.

Это делает ваш код более сложным, но это необходимо в ряде ситуаций. 

2
sprinter

Иногда Eclipse нуждается в хорошей очистке и перестройке всех проектов, и проблема исчезает.

0
Peteter