News Ticker

Java 8 Streams: .filter and Predicate Negation

Java 8 Streams

Recently there was an interesting discussion on the use of predicate negation in the .filter method on a stream by members of the LJC mailing list, so I thought it would be worth summarizing it in a blog post. The discussion was about ways to use .filter and to negate the predicate.

Code for this post is available in my GitHub account.

Question: How can you use .filter to negate the predicate

This is perhaps how you might think about doing,

Stream.of(1, 2, 3, 4, 5, 6, 7)
  .filter(((Predicate) c -> c % 2 == 0).negate())

but here are some alternative ways.

Answer 1: Write a predicate utility method

You can simplify this by writing a utility method that performs the negation.

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

Which results in much neater code.

Stream.of(1, 2, 3, 4, 5, 6, 7)
  .filter(not(c -> c % 2 == 0))

View source on GitHub

Answer 2: Use an identity function to convert the method reference to a Predicate

We use a utility method to convert a method reference to a predicate.

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

although the code is not as neat.

Stream.of("Cat", "", "Dog")
  .filter(predicate(String::isEmpty).negate())

References: Heinz’s Lambda Reduction Principle

Answer 3: Use the not (!) operator

Use the familiar, not operator.

Stream.of(1, 2, 3, 4, 5, 6, 7)
  .filter((c -> c % 2 != 0))

Stream.of("Cat", "", "Dog")
  .filter(str -> !str.isEmpty())

The code is much simpler and immediately familiar.

Conclusion

It is argued that method references are often harder to read and are trickier when refactoring than simple lambdas and that mixing lambdas and method references in a Stream chain is confusing to the reader. Reference: Java SE 8 Best Practices

When you use a method reference and want the IDE to create the method, IntelliJ creates this as a static method with the object as the first argument. Using the not operator avoids this.

Here are some useful references:

1 Comment on Java 8 Streams: .filter and Predicate Negation

  1. Was surprised that – after so many years of previous functional languages to learn lessons from – the intrinsically ambiguously named method “filter” was used at all in Java8.

    I much prefer a pair of methods: “accept” (or “select”) and “reject”. Doesn’t everyone?

Leave a Reply

%d bloggers like this: