Reputation: 720
I need to compose a stream operation with a predicate based on a boolean function. Found a workaround via rethrowing a method's argument as a predicate, as shown:
public <T> Predicate<T> pred(final Predicate<T> aLambda) {
return aLambda;
}
public List<String> foo() {
return new ArrayList<String>().stream() //of course, this does nothing, simplified
.filter(pred(String::isEmpty).negate())
.collect(Collectors.toList());
}
The 'pred' method seems to do nothing, however not this:
public List<String> foo() {
return new ArrayList<String>().stream()
.filter((String::isEmpty).negate())
.collect(Collectors.toList());
}
nor any in-line conversion:
public List<String> foo() {
return new ArrayList<String>().stream()
.filter(((Predicate)String::isEmpty).negate())
.collect(Collectors.toList());
}
seems to work. Fails with the error
The target type of this expression must be a functional interface
What the fancy conversion happens in the 'pred(...)' method?
Upvotes: 9
Views: 13801
Reputation: 49606
You could write a utility method:
class PredicateUtils {
public static <T> Predicate<T> not(Predicate<T> predicate) {
return predicate.negate();
}
}
and use it as follows:
.filter(not(String::isEmpty))
I believe it's more readable than casting to a Predicate<T>
:
.filter(((Predicate<String>)String::isEmpty).negate())
Though I would go with a simple lambda:
s -> !s.isEmpty()
What the fancy conversion happens in the
pred(...)
method?
You have specified a context - the type to work with. For instance, a String::isEmpty
could be a Function<String, Boolean>
, or Predicate<String>
, or my @FunctionalInterface
, or something else.
You clearly said that you were expecting a Predicate<T>
, and you would return an instance of the Predicate<T>
. The compiler is now able to figure out what the type you want to use.
Upvotes: 8
Reputation: 44918
Your third version almost worked:
Arrays.<String>asList("Foo", "Bar", "").stream()
.filter(((Predicate<String>)String::isEmpty).negate())
.collect(Collectors.toList());
This seems to compile just fine.
Upvotes: 2
Reputation: 691715
You can use
((Predicate<String>) String::isEmpty).negate()
(note the use of the proper generic type)
or (preferred):
s -> !s.isEmpty()
which is way simpler and readable.
Upvotes: 6