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 ?
The Functional Interface PREDICATE is defined in the java. util. function package. It improves manageability of code, helps in unit-testing them separately, and contain some methods like: isEqual(Object targetRef) : Returns a predicate that tests if two arguments are equal according to Objects.
compose() The Java Function compose() method composes a new Function instance from the Function instance it is called on, and the Function instance passed as parameter to the compose() method.
We can also use Predicate.or() to combine Predicates.
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)
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