Effective Java - ITEM 42 Prefer lambdas to anonymous classes

Posted by Tim Lin on 2021-01-24

Effective Java - ITEM 42 Prefer lambdas to anonymous classes

使用 lambdas 優先於 anonymous classes

簡化 sort Comparator

傳統上 sort 要使用 Comparator 的 anonymous class 方式完成

1
2
3
4
5
6
7
8
List<String> words = List.of("tim", "beef", "lin");

Collections.sort(words, new Comparator<>() {
@Override
public int compare(String s1, String s2) {
return Integer.compare(s1.length(), s2.length()) ;
}
}) ;

但可以更簡潔, 使用 lambdas 來完成,

下面可以看到 lambdas 都忽略了 type, 不需要寫!

1
Collections,sort(words, (s1, s2) -> Integer.compare(s1.length(), s2.length()));

那是因為 compiler 都有幫你做了 type inference 但前提是

在一開始的資料上, 你應該好好的宣告 List, 而不是只是 List

也可以利用新提供的 comparingInt() 和 method reference(String::length) 來完成

1
2
3
4
Collections.sort(words, Comparator.comparingInt(String::length)) ;

// Java 8 提供的
words.sort(comparingInt(String::length));

簡化 ITEM34

之前的 ITEM34 有一段程式碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Enum type with constant-specific class bodies and data
public enum Operation {
PLUS("+") {
public double apply(double x, double y) { return x + y; }
},
MINUS("-") {
public double apply(double x, double y) { return x - y; }
},
TIMES("*") {
public double apply(double x, double y) { return x * y; }
},
DIVIDE("/") {
public double apply(double x, double y) { return x / y; }
};

private final String symbol;

Operation(String symbol) { this.symbol = symbol; }

@Override
public String toString() { return symbol; }

public abstract double apply(double x, double y);
}

ITEM34 可以藉由多定義 DoubleBinaryOperator , 來簡化成 lambdas

1
2
3
4
5
6
// 原本 Operation(String symbol) { this.symbol = symbol; }
// 多了 DoubleBinaryOperator
Operation(String symbol, DoubleBinaryOperator op) {
this.symbol = symbol;
this.op = op;
}
1
2
3
4
public Enum Operation {
PLUS ("+", (x, y) -> x + y)
....
}

幾個重點整理

  • 應該好好的宣告 List, 而不是只是 List
  • lambda 不宜超過 3 行, 超過就該考慮重構了

This

  • 在 lambdas 中, this 指向 enclosing instance
  • 在 anonymous class, this 指向 anonymous class instance
  • 所以在 body 內如果想要訪問成員變數還是方法, 應該就要使用 anonymous class

Serialize & Deserialize

  • 跟 anonymous class 一樣, lambdas 不應該拿來序列化, 反序列化
  • 如果真的要做序列化, 像是 Comparator, 要用 private static nested class

Conclusion

無論如何, 除非你要實例化, 不要使用 anonymous class, 使用 lambdas!