Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to suitably compose Predicate and Function in a Java function?

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 ?

like image 831
fdelsert Avatar asked Apr 14 '17 16:04

fdelsert


People also ask

What is predicate and function in Java?

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.

What is the compose function in Java?

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.

How do you combine two Predicates in Java?

We can also use Predicate.or() to combine Predicates.


1 Answers

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)
like image 152
fdelsert Avatar answered Oct 16 '22 17:10

fdelsert