續集聚焦集合框架的進階陷阱與特性:List 與陣列語義差異、Iterator 隱藏能力、非集合 Iterable、可變鍵的 HashMap 陷阱、equals() 與 Comparable 的 Set 語義衝突。
List 維護「插入順序」(Ordinal),刪除元素後續元素前移填補空位;陣列維護「固定位置」(Position),刪除實為覆蓋 null。
List list = new ArrayList<>(Arrays.asList("a","b","c"));
list.remove(1); // 刪除 "b",list 變為 ["a","c"],"c" 從位置2移到位置1
String[] arr = new String[]{"a","b","c"};
arr[1] = null; // 陣列變為 ["a", null, "c"],位置不變
iterator.remove() 避免 ConcurrentModificationExceptionhasPrevious()、previous()、add()、set(),支援滑動結果集、反向遍歷實現 Iterable 介面,iterator() 返回按需生成元素的 Iterator,可用增強 for 遍歷文件、資料庫結果、網絡流等無限序列。
public static Iterable readLines(String filename) {
return () -> new Iterator() {
String line = readFirstLine();
public boolean hasNext() { return line != null; }
public String next() { String r=line; line=readNextLine(); return r; }
public void remove() { throw new UnsupportedOperationException(); }
};
}
// 使用:for (String line : readLines("big.log")) System.out.println(line);
優勢:不載入全文到記憶體。缺點:Iterator 結束前無法關閉底層資源。
若 Key 的 hashCode() 依賴可變字段,修改字段後 map.get(key) 返回 null,因雜湊桶位置已變。
Person p = new Person("Ted", "Neward", 39);
map.put(p, "value");
p.setLastName("Finkelstein"); // hashCode 改變
map.get(p); // 返回 null!物件在錯誤桶中
鐵律:絕不使用可變對象作 HashMap Key。
TreeSet 使用 Comparator/Comparable 判斷相等(compareTo==0),而非 equals()。兩者語義不同:
實現 Comparable 時必須確保 compareTo==0 ⇔ equals(),否則 Set 行為違反直覺。
Concurrent Collections(java.util.concurrent),JDK 5 引入的併發集合金礦。