Florian Schaetz
Florian Schaetz

Reputation: 10662

Create Predicate with and/or/negate methods in one statement?

java.util.function.Predicate has some useful methods like and, or, etc. which are more concise than creating a bracket orgy with multiple logical operators. Unfortunately there seems to be no way to use these functions without actually having a Predicate explictely first...

Predicate<String> predicate = String::isEmpty;
Predicate<String> predicateWithAnd = predicate.and( MyClass::testSomething ); 

Is there a way to create the 2nd Predicate in only one statement (thus "saving" a variable), like...

Predicate<String> predicateWithAnd = (String::isEmpty).and( MyClass::testSomething );  // That doesn't seem to work ;-)

Just curious...

Upvotes: 3

Views: 2239

Answers (2)

ByeBye
ByeBye

Reputation: 6966

Yes, you need to cast your lambda on Predicate type, where T is your type. Example with Person class.

Predicate<Person> a = ((Predicate<Person>)p -> p.getId() > 2)
                                     .and(p -> p.getPrice() > 100);

Upvotes: 6

Tagir Valeev
Tagir Valeev

Reputation: 100329

It's not very clear why str -> str.isEmpty() && MyClass.testSomething(str) is called as "bracket orgy". It's readable and short. In general these and, or methods are useful when you have ready Predicate objects. You should not use them to combine method references or lambdas.

If you really want to use method references, there are few tricks. First, you may create your own utility class like this:

import java.util.function.Predicate;
import java.util.stream.Stream;

public class Predicates {
    @SafeVarargs
    public static <T> Predicate<T> and(Predicate<T>... preds) {
        return Stream.of(preds).reduce(Predicate::and).orElse(x -> true);
    }

    @SafeVarargs
    public static <T> Predicate<T> or(Predicate<T>... preds) {
        return Stream.of(preds).reduce(Predicate::or).orElse(x -> false);
    }
}

And use it like this:

import static mypackage.Predicates.*;

Predicate<String> predicateWithAnd = and(String::isEmpty, MyClass::testSomething);

Alternatively you may create only one quite useless static method:

public static <T> Predicate<T> pred(Predicate<T> pred) {
    return pred;
}

And use it like this:

pred(String::isEmpty).and(MyClass::testSomething);

This is much shorter than explicit type cast. However I would still recomment to stay with explicit lambda like str -> str.isEmpty() && MyClass.testSomething(str).

Upvotes: 5

Related Questions