Effective Java for Lambda Functions, Method References and Standard Interfaces

Java 8 was released in 18th March 2014 and it introduced beautiful features in order to write better-looking code. Functional interfaces, lambdas, and method references were added to make easier to create function objects.

Ending 2017, Joshua Bloch released the third edition of The Effective Java [1], one of my favorite technical books, and the good news are that it covers the best practices for writing code using the features added in Java 7, 8, and 9. The author has included 3 items devoted to lambdas and method references, of which I would like to derive some “Best Practices” in order to be “More Effective Java”.

No alt text provided for this image


Item 1: Prefer Lambdas to Anonymous Classes

One of the most common criticisms for Java is its verbosity. Do you remember how verbose Swing was? For example, in the past, if you wanted to add an action for a button, you had to do something like this:

button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent evt) {
        System.out.println(“Classic way of an anonymous class.”);
    }
});

Now, how would it look with a lambda expression?

button.addActionListener(e -> System.out.println(“Lambda expression”
 + “ with Java 8.”));

A Java lambda expression is a function which can be created without belonging to any class, they can be managed as an object and executed on demand. The primary advantage of lambdas over anonymous classes is that they are more succinct.

The best practice here is “lambdas are the best way to represent small function objects. Don’t use anonymous classes for function objects unless you have to create instances of types that aren’t functional interfaces” [1].

Item 2: Prefer Method References To Lambdas

method reference is a reference to a function through an object without parameter signature. The format is below:

object::function

Method references often provide a more succinct alternative to lambdas. The theory said that “there’s nothing you can do with a method reference that you can’t also do with a lambda” [1]

Occasionally, a lambda could be more succinct than a method reference, like in next example:

service.execute(GoshThisClassNameIsHumongous::action);

The lambda equivalent looks like this:

service.execute(() -> action());

So, considering that the method references usually result in shorter, clearer code, the best practice is “to use method references where they aren’t, stick with lambdas”

Item 3: Favor the use of Standard Functional Interfaces

Any interface with a SAM (Single Abstract Method) is a functional interface, and its implementation may be treated as a lambda expression. The java.util.function package provides a large collection of standard functional interfaces. So, if one of the standard functional interfaces does the job, you should use it.

There are forty-three interfaces, but it is not necessary to remember them all. If you remember six basic interfaces, you can derive the rest using the strategy documented[2]. Some examples of the six basic functional interfaces are:

UnaryOperator<T>                        String::toLowerCase
BinaryOperator<T>                       BigInteger::add
Predicate<T>                            Collection::isEmpty
Function<T,R>                           Arrays::asList
Supplier<T>                             Instant::now
Consumer<T>                             System.out::println

So, here the best practice is ”to use the standard interfaces provided in java.util.function.Function, but keep our eyes open for the relatively rare cases where we would be better off writing our own functional interfaces” [1].

Extended Best Practices

Item 4: Use the @FunctionalInterface Annotation

When you use the @FunctionalInterface annotation, the compiler triggers an error in response to any attempt to break the predefined structure of a functional interface. Next the best practice:

Prefer:
@FunctionalInterface
public interface Foo {
    String method();
}
instead of just:
public interface Foo {
    String method();
}

Item 5: Keep Lambda Expressions Short And Self-explanatory

Remember that the lambdas should be an expression, not a narrative. Despite its concise syntax, lambdas should precisely express the functionality they provide. So the best practice is:

Prefer:
Comparator<DeveloperFactory> byName =
    (o1, o2) -> o1.getName().compareTo(o2.getName());
instead of:
Comparator<Developer> byName =
    (DeveloperFactory o1, DeveloperFactory o2) -> { 
         String developerName1 = o1.getLastName(); 
         String developerName2 = o2.getLastName(); 
         return developerName1.compareTo(developerName1);
};

Occasionally, a lambda will be more succinct than a method reference, but in somes cases it couldn’t happen. So, for these cases:

No prefer:
service.execute(GoshThisClassNameIsHumongous::action);
instead of:Item 7: Avoid Blocks of Code in Lambda’s Body

In an ideal situation, the lambdas should be written in one line of code. But if you have a large block of code, the lambda’s functionality won’t be clear. So:

Prefer:
Something some = param -> doSomething(param);
private String doSomething(String param) {
    //many lines of code
    return something;
}
instead of:
Something some = param -> {
    //many lines of code
    return something;
};

Item 6: Avoid specifying parameter types

As I mentioned, you should omit the types of the lambda parameters unless their presence is required. The best practice here is if the compiler generates an error telling you it can’t infer the type of a lambda parameter, then specify it, in other case no.

Item 7: Avoid parentheses around a single parameter

Lambda syntax requires parentheses only around more than one parameter or when there is no parameter at all. That is why it is safe to make your code a little bit shorter and to exclude parentheses when there is only one parameter.

Item 8: Avoid return statement and braces

Braces and return statements are optional in one-line lambda bodies. So, you should omit them for clarity.

For the last three items, prefer:
some -> some.doSomething();
instead of this:
(Some some) -> { return some.doSomething() };


要查看或添加评论,请登录

Yury Ni?o Roa的更多文章

社区洞察

其他会员也浏览了