2021/03/31

[筆記] Effective Java #61 基本類型優先於裝箱基本類型

Effective Java 3rd 簡體中文版筆記 #61 基本類型優先於裝箱基本類型
Java 類型由兩部分組成,包含基本類型 (primitive) 引用類型 (reference type),前者像是 intdoubleboolean,後者像是 StringList 等。每一個基本類型都有一對應的引用類型,稱作裝箱基本類型 (boxed primitive),像是 IntegerDoubleBoolean

基本類型與基本裝箱類型有三個主要區別:
  1. 基本類型只有數值,基本裝箱類型可為同一數值但不同實體。
  2. 基本裝箱類型會有 null。
  3. 基本類型比裝箱基本類型更節省時間及空間。
下面是 Comparator 的實作,它在大多數測試都是沒有問題的,但有一個嚴重的缺陷。假設執行 c.compare(new Integer(42), new Integer(42)),應該要回傳 0,但實際上會回傳 1,原因是在第一段比較 i < j 時,Integer 被自動拆箱為 int 作比較,接著來到第二段比較 i == j,這時的比較是針對引用,而不是針對數字本身。裝箱基本類型使用 == 來作比對是不正確的。
Comparator<Integer> c = (i, j) -> i < j ? -1 : (i == j ? 0 : 1);
c.compare(new Integer(42), new Integer(42));  // 1

Comparator<Integer> c = (iBoxed, jBoxed) -> {
    int i = iBoxed, j = jBoxed;
    return i < j ? -1 : (i == j ? 0 : 1);
};
下面這段程式碼會輸出什麼? 答案是會丟出例外 NullPointerException,因為 i 沒有初始化是 null,在 i == 42 比較時,當一項操作中混合基本類型與裝箱基本類型時,裝箱基本類型會自動拆箱 (unboxing)
static Integer i;
public static void main(String[] args) {
    if (i == 42)
        System.out.println("Unbelievable");
}
Longlong 交互使用時,比只使用 long 還要慢,因為會需要重複進行裝箱及拆箱等工作,所以在使用時應區分開來,避免混用。
public static void main(String[] args) {
    Long sum = 0L;
    for (long i = 0; i < Integer.MAX_VALUE; i++)
        sum += i;
    System.out.println(sum);
}
若是可以選擇,基本類型優先於裝箱基本類型。自動裝箱減少使用裝箱基本類型的繁瑣性,但是不會減低它的風險,像是上面提到的 == 的比對及 NullPointerException 的產生。

轉載請註明原文網址 https://cookieandcoketw.blogspot.com/2021/03/effective-java-61-boxed-primitive.html

沒有留言:

張貼留言