I created a function to filter with multiple predicates for which I perform a logical AND for them:
@SafeVarargs
public static <T> Stream<T> filter(Stream<T> source, Predicate<T>... predicates) {
return source.filter(Arrays.stream(predicates).reduce(predicates[0], Predicate::and));
}
When calling:
filter(IntStream.range(0, 10).boxed(), x -> x % 2 != 0, x -> x%3 == 0).forEach(System.out::println);
It works fine and prints 3 and 9. However when I pass a single predicate such as:
filter(IntStream.range(0, 10).boxed(), x -> x % 2 != 0).forEach(System.out::println);
I get a compilation error:
The target type of this expression must be a functional interface
Why is this?
For infos I use Eclipse Luna version 1.
This is a corner case for the compiler. In order to determine whether it should apply varargs wrapping of arguments into an array or simply pass an array, it needs to know the type of the last argument, however, in the case of a lambda expression it needs the invoked method signature to determine the type. But it’s clear what should happen as a lambda expression can never be an array type and so, javac
compiles it without problems.
One acceptable work-around would be to overload the method:
@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);
}
This would be an an acceptable work-around as it does not require any changes on the calling side while improving the efficiency for the single-arg case at the same time.
Please note that your varargs method allows zero arguments but will fail if called that way. So you should either, add another overload:
public static <T> Stream<T> filter(Stream<T> source) {
return source;
}
or make the method safe for the zero argument case:
@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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With