/ LAMBDA, CLEAN CODE, JAVA 8

Lambdas and Clean Code

As software developers, we behave like children. When we see shiny new things, we just have to play with them. That’s normal, accepted, and in general, even beneficial to our job…​ up to a point.

When Java started to provide annotations with version 5, there was a huge move toward using them. Anywhere. Everywhere. Even when it was not a good idea to. But it was new, hence it had to be good. Of course, when something is abused, there’s a strong movement against it. So that even when the usage of annotations may make sense, some developers might strongly be against it. There’s even a site about that (warning, trolling inside).

Unfortunately, we didn’t collectively learn from overusing annotations. With a lot of companies having migrated to Java 8, one start to notice a lot of code making use of lambdas like this one:

List<Person> persons = ...;
persons.stream().filter(p -> {
    if (p.getGender() == Gender.MALE) {
        return true;
    }
    LocalDate now = LocalDate.now();
    Duration age = Duration.between(p.getBirthDate(), now);
    Duration adult = Duration.of(18, ChronoUnit.YEARS);
    return age.compareTo(adult) > 0) {
        return true;
    }
    return false;
}).map(p -> p.getFirstName() + " " + p.getLastName())
  .collect(Collectors.toList());

This is just a stupid sample, but it gives a good feeling of the code I sometimes have to read. It’s in general longer and even more convoluted, or to be politically correct, it has room for improvement - really a lot of room.

The first move would be to apply correct naming, as well as move the logic to where it belongs to.

public class Person {

    // ...

    public boolean isMale() {
        return getGender() == Gender.MALE;
    }

    public boolean isAdult(LocalDate when) {
        Duration age = Duration.between(birthDate, when);
        Duration adult = Duration.of(18, ChronoUnit.YEARS);
        return age.compareTo(adult) > 0;
    }
}

This small refactoring already improves the readability of the lambda:

persons.stream().filter(p -> {
    if (p.isMale()) {
        return true;
    }
    LocalDate now = LocalDate.now();
    return p.isAdult(now);
}).map(p -> p.getFirstName() + " " + p.getLastName())
        .collect(Collectors.toList());

But it shouldn’t stop there. There’s an interesting bia regarding lambda: they have to be anonymous. Nearly all examples on the Web show anonymous lambdas. But nothing could be further from the truth!

Let’s name our lambdas, and check the results:

// Implementation details
Predicate<Person> isMaleOrAdult = p -> {
    if (p.isMale()) {
        return true;
    }
    LocalDate now = LocalDate.now();
    return p.isAdult(now);
};
Function<Person, String> concatenateFirstAndLastName = p -> p.getFirstName() + " " + p.getLastName();

// Core
persons.streams()
    .filter(isMaleOrAdult)
    .map(concatenateFirstAndLastName)

Nothing mind-blowing. Yet, notice that the stream itself (the last line) has become more readable, not hidden behind implementation details. It doesn’t prevent developers from reading them, but only if necessary.

Conclusion

Tools are tools. Lambdas are one of them, in a Java developer’s toolsbelt. But concepts are forever.

Nicolas Fränkel

Nicolas Fränkel

Developer Advocate with 15+ years experience consulting for many different customers, in a wide range of contexts (such as telecoms, banking, insurances, large retail and public sector). Usually working on Java/Java EE and Spring technologies, but with focused interests like Rich Internet Applications, Testing, CI/CD and DevOps. Also double as a trainer and triples as a book author.

Read More
Lambdas and Clean Code
Share this