整理Effective Java書中Item 28: Prefer lists to arrays心得筆記

主旨

提出使用lists優於arrays的部分。

點出問題

主要分成兩個重點

1.陣列是協變的(arrays are covariant):

T[] 可能包含T類別或任何T子類別如下

Number[] numbers = new Number[2];
numbers[0] = Integer.valueOf(18);
numbers[1] = Double.valueOf(3.14);

所以下面程式碼也是合法沒問題的,IntegerNumber的子類別

Integer[] ints = {1,2,3,4,5};
Number[] numbers = ints;

但是問題來了,如果其他開發人員沒注意寫了下面程式會怎樣?

Integer[] ints = {1,2,3,4,5};
Number[] numbers = ints;
...

numbers[0] = 3.14;

執行編譯完全沒問題,假設又沒有Unit test,等上線就爆了ArrayStoreException … 同樣的邏輯如果改用List改寫呢

List<Integer> ints = new ArrayList<>() {{
    add(1));
    add(2);
    add(3);
}};
List<Number> numbers = ints; //compiler error
numbers.add(3.14);

連編譯都無法執行….這裡就很明確告知開發使用不合法而避免錯誤。記得以前的主管是C語言背景的,很常要求我們在寫Java使用array自己控制index以及記憶體管理,所以沒有仔細測試一不小心就會出現問題,必須在型別處理就需要特別注意。

2.陣列是具體化的(arrays are reified):

陣列是在runtime時強制要求型別,而泛型則是在編譯時對型別約束。由於這些差異,要陣列跟泛型不是很好混用,像是new List<E>[]、new List<String>[]、new E[]都會發生編譯錯誤,因為在不是型別安全的,如果強制轉型可能產生ClassCastException,違反了泛型本質。

小結

陣列跟泛型有著不同的形態規則,陣列是協變的、具體化的,泛型是不變的、可消除的。這兩者不要混用。如果遇到編譯上型別的錯誤或警告盡可能地將array換成list。

參考延伸閱讀: