Ответ 1
Это угловой случай для компилятора. Чтобы определить, следует ли применять varargs, перенос аргументов в массив или просто передать массив, ему необходимо знать тип последнего аргумента, однако в случае выражения лямбда ему нужна сигнатура метода invoke, чтобы определить тип. Но его ясное, что должно происходить как выражение лямбда, никогда не может быть типом массива, и поэтому 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);
}