Item 42: Prefer lambdas to anonymous classes

Anonymous classes were adequate for the classic objected-oriented design patterns requiring function objects. Here’s a code snippet using an anonymous class.

// Anonymous class instance as a function object - obsolete! 
Collections.sort(words, new Comparator<String>() { 
    public int compare(String s1, String s2) { 
         return Integer.compare(s1.length(), s2.length()); 
    }
});

Interfaces with a single abstract method are now known as functional interfaces, and the language allows you to create instances of these interfaces using lambda expressions. Lambdas are similar in function to anonymous classes, but far more concise. Here’s how the code snippet above looks with the anonymous class replaced by a lambda. The boilerplate is gone:

// Lambda expression as function object (replaces anonymous class)
Collections.sort((s1, s2) -> Integer.compare(s1.length(),s2.length()));

The compiler deduces the types of lambda (Comparator<String>), of its parameters (s1 and s2), and of its return value (int) from context using type inference. You should omit the types of all lambda parameters unless their presence makes your program clearer.

There is one caveat regarding type inference. If you use raw types instead of generic types, the compiler will be unable to do type inference. As compiler performs type inference from generics, you’ll have to specify types manually in your lambdas.

Function Objects

As of Java 8, lambdas are the best way to represent small function objects. A function can be passed as a parameter using compose and andThen functions in Function<T, R> interface. Here’s a code snippet using compose function:

Function<Integer, Integer> multiply = (value) -> value * 2;
Function<Integer, Integer> add = (value) -> value + 3;

//Returns a composed function that first applies the before function to its input, and then applies this function to the result.
Function<Integer, Integer> addThenMultiply = multiply.compose(add);

//Applies this function to the given argument.
Integer result1 = addThenMultiply.apply(3);
System.out.println("Function: (3 + 3) * 2 " + result1);

Reasons not to use Lambda

If a computation isn’t self-explanatory or exceeds a few lines, don’t put it in a lambda. One line is ideal for lambda, and three lines is a reasonable maximum. If you violate this rule, it can cause serious harm to the readability of your programs.

You shouldn’t serialize a lambda (or an anonymous class instance). Lambdas share with anonymous classes the property that you can’t reliably serialize and deserialize them across implementations.

Leave a Reply

Your email address will not be published. Required fields are marked *