Over a million developers have joined DZone.

Writing Clean Predicates with Java 8

DZone's Guide to

Writing Clean Predicates with Java 8

· Java Zone ·
Free Resource

Get the Edge with a Professional Java IDE. 30-day free trial.


Writing in-line lambda expressions and using the stream interfaces to perform common operations on collections can be awesome. Assume the following example:

List<Person> getAdultMales (List<Person> persons) {
  return persons.stream().filter(p -> 
    p.getAge() > ADULT &&
    P.getSex() == SexEnum.MALE 

That’s fun! But things like this also lead to software that is costly to maintain. At least in an enterprise application, where most of your code handles business logic, your development team will grow the tenancy to write the same similar set of predicate rules again and again. That is not what you want on your project.  It breaks three important principles for growing maintainable and stable enterprise applications:

  • DRY (don’t repeat yourself): writing code more than once is not a good fit for a lazy developer ;)It also makes your software more difficult to maintain because it becomes harder to make your business logic consistent
  • Readability: following clean-code best practices, 80% of writing code is reading the code that already exists. Having complicated lambda expressions is still a bit hard to read compared to a simple one-line statement.
  • Testability: your business logic needs to be well-tested. It is adviced to unit-test your complex predicates. And that is just much easier to do when you separate your business predicate from your operational code.

And from a personal point of view… that method still contains too much boilerplate code…


Fortunately, we have a very good suggestion in the world of unit testing on how we could improve on this.

Imagine the following example:

import static somepackage.PersonPredicate;
List<Person> getAdultMales (List<Person> persons) {
  return persons.stream().filter(

What we did here was:

  • create a PersonPredicate class
  • define a “factory” method that creates the lambda predicate for us
  • statically import the factory method into our old class

This is how such a predicate class could look like, located next to your Person domain entity:

public PersonPredicate {
  public static Predicate<Person> isAdultMale() {
    return p -> 
      p.getAge() > ADULT &&
      p.getSex() == SexEnum.MALE; 

Wait… why don’t we just create a “isMaleAdult” boolean function on the Person class itself like we would do in domain driven development? I agreed, that is also an option… but as time goes on and your software project becomes bigger and loaded with functionality and data… you will again break your clean code principles:

  • the class becomes bloated with all kind of function and conditions
  • your class and tests become huge, more difficult to handle and change (*)

(*) and yes… even if you do your best to separate your concerns and use composition patterns


Working with domain objects, we can imagine that some operations (such as filter) are often executed on domain entities. Taking that into account, it would make sense to let our entities implement some interface that offers us some default methods.

For example:

public interface DomainOperations<T> {
  default List<T> filter(Predicate<T> predicate) {
    return persons.stream().filter( predicate )

When our Person entity implements this interface, we can clean-up our code even more:

List<Person> getAdultMales (List<Person> persons) {
  return persons.filter( isAdultMale() );

And there we go…


Moving your predicates to a Predicate helper class offers some good advantages in the long run:

  • Predicate classes are easy to test and change
  • Your domain objects remain clean and focussed on representing your domain, not your business logic
  • You optimize the re-usability of your code and, in the end, reduce your maintenance
  • You seperate your business from operational concerns


Clean Code: A Handbook of Agile Software Craftsmanship [Robert C. Martin]

Practical Unit Testing with JUnit and Mockito [Tomek Kaczanowski]

State of the Collections [http://cr.openjdk.java.net/~briangoetz/lambda/collections-overview.html]


The code above is served as an example to illustrate the principles I wanted to discuss. However, I did not proof-run this code yet (it’s still on my todo list). Some modifications may be needed for your project.

Get the Java IDE that understands code & makes developing enjoyable. Level up your code with IntelliJ IDEA. Download the free trial.


Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}