The purpose is to create a new Predicate usable in a stream filter :
myCollectionOfElement
.stream()
.filter(
MyStaticHelperClass.compose(MyStaticHelperClass.getSubElement1OfTheElement(),MyStaticHelperClass.getPredicate1OnSubElement1()))
.sorted(MyStaticHelperClass.getOtherSubElement().reversed())
.limit(10)
.collect(Collectors.toList())
getSubElement1OfTheElement()
returns Function<E,S>
(E contains a S property)
getPredicate1OnSubElement1()
returns Predicate<S>
I use static functions to expose method references and functions. I do this because the stream is called in a Velocity template and this context doesn't support lambda syntax and method reference. I don't want to create a static function for all possible combinaisons, so I really want them to be composable.
For example here, I don't want to have a static getPredicate1OnElementThatCheckProperty1OnTheSubElement1()
because I can compose getSubElement1OfTheElement()
and getPredicate1OnSubElement1()
.
So I need a compose function :
// returns a new Predicate constructed by applying Predicate predicate on the result of Function function
public static <E,S> Predicate<E> compose(Function<E,S> function, Predicate<S> predicate)
// most intuitive : lambda
return value -> predicate.test(function.apply(value));
// with method references
return function.andThen(predicate::test)::apply;
// predicate.compose is not available because Predicate interface doesn't extends Function interface
inspired by Is there a convenience method to create a Predicate that tests if a field equals a given value?
// step by step with variables
Function <S,Boolean> predicateFunction = predicate::test;
// a kind of @FunctionalInterface implicit "conversion" ? Predicate -> Function.
// is that safe ?
Function <E,Boolean> composed = function.andThen(predicateFunction::apply);
return composed::apply;
Edit :
It's called a cast context : https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html
// the implementation of my compose can also be this ugly one-liner :
return ((Function <S,Boolean>)predicate::test).compose(function)::apply;
So, we cannot implement a generic compose function taking any functional interface (in my case Function and Predicate) because the name of the abstract method differs for each interface (test and apply in my case).
I'm OK with that.
To conclude, what I really need is two static functions, one that converts a Predicate to a Function and the opposite. Every Predicate will be used as a Function and the final operation will convert the composed Function to Predicate in order to match with the parameter type of the filter function.
public static <S> Function<S,Boolean> predicateToFunction(Predicate<S> predicate){
return predicate::test;
}
public static <S> Predicate<S> functionToPredicate(Function<S,Boolean> function){
return function::apply;
}
Is that correct ?
If so, is there any interest in releasing the bounds in the function signature ?
I answer my own questions.
Use lambda :
value -> predicate.test(function.apply(value));
Or if you really want/have to write a compose function, signature must be something like :
public static <E,S> Predicate<E> compose(Function<E,S> function, Predicate<? super S> predicate)