Writing Clean Predicates with Java 8

in-line predicates can create a maintenance nightmare.

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 
  ).collect(collectors.<person>tolist());
}

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:

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

imports to the rescue!

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(
    isadultmale()
  ).collect(collectors.<person>tolist());
}

what we did here was:

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:

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

adding some defaults…

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 )
      .collect(collectors.<person>tolist());
 }
}

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…

conclusion

moving your predicates to a predicate helper class offers some good advantages in the long run:

references

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]

notes

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.

 

 

 

 

Top