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:

4 responses to “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?

    Like

    1. Agreed 100%. But if we must keep “filter”, how about a “filterOut”?

      Like

  2. […] there is no easy way to negate a predicate lambda without first wrapping in a Predicate […]

    Like

  3. […] and collected to a new List. In the following code snippet the inline array is transformed into a stream so that mapping can be […]

    Like

Leave a comment

Trending