There are several ways, but I agree with @shmosel. Improving readability will be small.
One possible solution:
<V, P> Predicate<? super P> compare(Function<P, V> valueFunction, Predicate<V> matchPredicate) {
return p -> matchPredicate.test(valueFunction.apply(p));
}
A call to this method will look like this:
stream().filter(compare(P::thisReturnsAString, s -> s.endsWith(comparisonString)))
Where Pis the type of your object. A slightly adapted version, which, however, can lead to many overloaded methods:
<V, C, P> Predicate<? super P> compare(Function<P, V> valueFunction, BiPredicate<V, C> matchPredicate, C value) {
return p -> matchPredicate.test(valueFunction.apply(p), value);
}
A call to this method might look like this:
stream().filter(compare(P::thisReturnsAString, String::endsWith, comparisonString))
. , ; -)
EDIT: @shmosel Predicate vs Function