Predicate from Function Reference (of boolean type)

I need to compose a stream operation with a predicate based on a boolean function. Found a workaround via rethrowing a method’s argument as a predicate, as shown:

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

public List<String> foo() {
    return new ArrayList<String>().stream() //of course, this does nothing, simplified
            .filter(pred(String::isEmpty).negate())
            .collect(Collectors.toList());
}

The ‘pred’ method seems to do nothing, however not this:

public List<String> foo() {
    return new ArrayList<String>().stream() 
            .filter((String::isEmpty).negate()) 
            .collect(Collectors.toList());
}

nor any in-line conversion:

public List<String> foo() {
    return new ArrayList<String>().stream() 
            .filter(((Predicate)String::isEmpty).negate())
            .collect(Collectors.toList());
}

seems to work. Fails with the error

The target type of this expression must be a functional interface

What the fancy conversion happens in the ‘pred(…)’ method?

Solution:

You could write a utility method:

class PredicateUtils {

    public static <T> Predicate<T> not(Predicate<T> predicate) {
        return predicate.negate();
    }

}

and use it as follows:

.filter(not(String::isEmpty))

I believe it’s more readable than casting to a Predicate<T>:

.filter(((Predicate<String>)String::isEmpty).negate())

Though I would go with a simple lambda:

s -> !s.isEmpty()

What the fancy conversion happens in the pred(...) method?

You have specified a context – the type to work with. For instance, a String::isEmpty could be a Function<String, Boolean>, or Predicate<String>, or my @FunctionalInterface, or something else.

You clearly said that you were expecting a Predicate<T>, and you would return an instance of the Predicate<T>. The compiler is now able to figure out what the type you want to use.

Should functional interfaces be called directly?

I built a few classes that implement functional interfaces so that they can be reused, these include Predicates, Functions, etc.

These work great when I pass a new instance into a collection stream, for example:

myList.stream().filter(new PrimeNumberPredicate())...

Today I found an engineer on my team trying to reuse a predicate by creating and calling a predicate directly:

boolean result = new PrimeNumberPredicate().test(myData);

I find this code a bit verbose, and I’d like to ask if there is another way to write this so that I could do the test without explicitly calling test() on a single object.

Solution:

I wouldn’t do either. The fun of functional interfaces is that you don’t have to explicitly implement any particular interface, nor create useless objects. All you need is a method that does what you want and you can bend it to your functional will.

Define the predicate function staticly:

class PrimeNumbers {
    public static boolean isPrime(int number) {
        ...
    }
}

Then use it in a stream like so:

myList.stream().filter(PrimeNumbers::isPrime)...

Non-functional code like your co-worker’s could skip instantiating an object and call the function directly:

boolean result = PrimeNumbers.isPrime(myData);

This has the advantage of letting you name the class and method naturally, rather than “predicate” or “test” or “apply”.

Combine two Functions in Java8

In isReadyToDeliver method if all products in order is available (ProductState.AVAILABLE) and if order state is ready to send (OrderState.READY_TO_SEND), method must return true.
I wrote both two part but I couldn’t combine them in return phrase,

I wrote return orderState.andThen(productState) but get this error:

The method andThen(Function<? super Boolean,? extends V>) in the type Function<Order,Boolean> is not applicable for the arguments (Function<Order,Boolean>)

public class OrderFunctions  {

    public Function<Order, Boolean> isReadyToDeliver() {            
        Function<Order, Boolean> orderState = o -> o.getState() == OrderState.READY_TO_SEND;            
        Function<Order, Boolean>  productState = 
                o -> o.getProducts()
                    .stream()
                    .map(Product -> Product.getState())
                    .allMatch(Product -> Product == ProductState.AVAILABLE);

        return ????? ; 
       //return  orderState.andThen(productState);
       //error: The method andThen(Function<? super Boolean,? extends V>) in the type Function<Order,Boolean> is not applicable for the arguments (Function<Order,Boolean>)      
    }
}

In case other classes are needed:

enum OrderState {CONFIRMED, PAID, WAREHOUSE_PROCESSED, READY_TO_SEND, DELIVERED }

enum ProductType { NORMAL, BREAKABLE, PERISHABLE }

public class Order {

    private OrderState state;
    private List<Product> products = new ArrayList<>();

    public OrderState getState() {
        return state;
    }

    public void setState(OrderState state) {
        this.state = state;
    }

    public Order state(OrderState state) {
        this.state = state;
        return this;
    }

    public List<Product> getProducts() {
        return products;
    }

    public void setProducts(List<Product> products) {
        this.products = products;
    }

    public Order product(Product product) {
        if (products == null) {
            products = new ArrayList<>();
        }
        products.add(product);
        return this;
    }
}

public class Product {

    private String code;
    private String title;
    private ProductState state;

    public ProductState getState() {
        return state;
    }

    public void setState(ProductState state) {
        this.state = state;
    }

    public Product state(ProductState state) {
        this.state = state;
        return this;
    }
}

Solution:

If you change isReadyToDeliver() to return Predicate<Order> then you will be able to combine two predicates with .and(Predicate another) function:

public Predicate<Order> isReadyToDeliver() {
    Predicate<Order> orderState = o -> o.getState() == OrderState.READY_TO_SEND;

    Predicate<Order> productState =
                o -> o.getProducts()
                   .stream()
                   .map(Product -> Product.getState())
                   .allMatch(Product -> Product == ProductState.AVAILABLE);

    return orderState.and(productState);
}

Your example with functions composition didn’t work, because when you compose functions f and g, g takes as a parameter value that f function returns. In your case it was broken, because orderState expected Order and return Boolean and it this case orderState.andThen() expected a function that takes Boolean as a parameter and returns something else. This requirement was not satisfied, because productState expected Order and returned Boolean. This is exactly what following error said:

error: The method andThen(Function) in the type Function is not applicable for the arguments (Function)

But if for some reason you want to stay with Function<Order, Boolean> then you will have return a lambda like:

public Function<Order, Boolean> isReadyToDeliver() {
    Function<Order, Boolean> orderState = o -> o.getState() == OrderState.READY_TO_SEND;

    Function<Order, Boolean> productState =
            o -> o.getProducts()
                    .stream()
                    .map(Product -> Product.getState())
                    .allMatch(Product -> Product == ProductState.AVAILABLE);


    return (order) -> orderState.apply(order) && productState.apply(order);
}