javapredicate

Java Predicate<T> with common input parameters


I have the following 3 methods in Java written with the help of Predicate:

public static final Predicate<CustomerType> function1 = ct ->
        "OWNER".equals(ct.getFactType()) && "FULL".equals(ct.getFactValue());


public static final Predicate<CustomerType> function2 = ct ->
        "OWNER".equals(ct.getFactType()) && ("NONFULL".equals(ct.getFactValue()) || "FULL".equals(ct.getFactValue()));


public static final Predicate<CustomerType> function3 = ct ->
        ("INDIRECT".equals(ct.getFactType()) || "NONINDIRECT".equals(ct.getFactType()))
                && "YES".equals(ct.getFactValue());

As you can see, there is a lot of common elements on the three functions (eg. CustomerValue.getFactValue and CustomerValue.getFactType).

Is there a way to give these inputs as input parameters in every three functions? If yes, how?

I have the following method which should give me a boolean result based on the predicates:

private boolean checkJohn(List<CustomerType> custTypes) {
    return custTypes.stream().anyMatch(Functional.method2);
}

private boolean checkJoan(List<CustomerType> custTypes) {
    return custTypes.stream().anyMatch(Functional.method1);
}

As the number of the input parameters is different, because the both parameters can have either A or B value, I am a little stucked...


EDIT:

If I have the following:

public static final BiPredicate<String, CustomerType> functionName = (ct, ft) ->
        ("NATPERSON".equals(ct) && ("INDIRECT".equals(ft.getFactType()) && "YES".equals(ft.getFactValue())))
                || ("NONNATPERS".equals(ct) && ("NONINDIRECT".equals(ft.getFactType()) && "YES".equals(ft.getFactValue())));

...this works fine...

But if I create :

Predicate<PersonType> IS_NATPERSON = wrap("NATPERSON"::equals); 
Predicate<PersonType> IS_NONNATPERSON = wrap("NONNATPERSON"::equals);

with the followinf wrap:

private static Predicate<PersonType> wrap(Predicate<String> predicate) {
    return ft -> predicate.test(ft.getType().getCustomerType());
}

And try the call:

public static final BiPredicate<PersonType, CustomerType> functionName2 = (IS_NATPERSON.and((IS_INDIRECT).and(IS_YES))).or(IS_NONNATPERSON.and((IS_NONINDIRECT).and(IS_YES)));

Then I get that :

and (java.util.function.Predicate<? super PersonType>) in Predicate cannot be applied to (java.util.function.Predicate<CustomerType>)

Any idea?


Solution

  • You can use the BiPredicate type, which takes in two arguments. Then it will be the caller's job to invoke .getFactType() and .getFactValue().

    You could also simplify reading this by creating constants for each of the pieces and then composing them using the .and and .or methods:

    static final BiPredicate<String, String> IS_OWNER = (t, v) -> "OWNER".equals(t);
    // Etc
    
    static final BiPredicate<String, String> f1 = IS_OWNER.and(IS_FULL);
    
    // Using a BiPredicate by unwrapping a customer type:
    if (f1.test(ct.getFactType(), ct.getFactValue())) {
    

    Ideally, the type of fact type and fact value would be different so that they are not accidentally confused.

    If you didn't want to push the unwrapping responsibility to the caller, you could write a static helper which turns a BiPredicate<String, String> into a Predicate<CustomerType>:

    static Predicate<CustomerType> wrap(BiPredicate<String, String> bp) {
        return ct -> bp.test(ct.getFactType(), ct.getFactValue());
    }
    
    static final Predicate<CustomerType> IS_OWNER = wrap((t, v) -> "OWNER".equals(t));
    // Etc
    
    static final Predicate<CustomerType> f1 = IS_OWNER.and(IS_FULL);