java.util.Collection 為所有集合類根類型。關鍵方法語意:
boolean add(Object):回傳值非表示成功與否(失敗會拋例外),而是表示「集合內容是否發生變化」(元素數量/位置改變)。同理 addAll/remove/removeAll/retainAll。toArray() / toArray(Object[]):後者回傳陣列型別與參數一致;參數陣列足夠大則回傳該陣列(內容填入),不足則新建陣列;若參數陣列較大,多餘位置設為 null。iterator():回傳 Iterator,統一遍歷介面。無 Iterator 時,客戶端必須知悉內部結構:
// 陣列用索引
for (int i=0; i<list.size(); i++) { ... list.get(i) ... }
// 鏈表用指標
while ((e = e.next()) != null) { ... e.data() ... }
耦合度高、無法復用、換集合類別需重寫遍歷邏輯。Iterator 模式統一為:
for (Iterator it = c.iterator(); it.hasNext(); ) { ... it.next() ... }
奧義在於:遍歷狀態(游標、是否有下一個)由 Iterator 維護,集合類別透過工廠方法 iterator() 產生對應的 Iterator,客戶端僅操作 Iterator 介面。
public interface Iterator {
boolean hasNext();
Object next();
void remove();
}
典型用法:
for (Iterator it = c.iterator(); it.hasNext(); ) {
Object o = it.next();
// 處理 o
}
JDK 1.5 引入增強 for 迴圈:for (Type t : c) { ... }。各集合回傳不同具體 Iterator(ArrayIterator、SetIterator 等),但皆實作 Iterator 介面,體現面向介面程式設計。
private class Itr implements Iterator {
int cursor = 0; // 下一次 next() 回傳的索引
int lastRet = -1; // 上一次回傳的索引
int expectedModCount = modCount; // 快照 modCount,用於檢測並發修改
}
public boolean hasNext() {
return cursor != size();
}
public Object next() {
checkForComodification();
try {
Object next = get(cursor);
lastRet = cursor++;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
AbstractList 持有 modCount (初始 0),每次結構性修改 (add/remove 等) 遞增。Itr 建構時快照 expectedModCount,關鍵處呼叫 checkForComodification():
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
ConcurrentModificationException 為 RuntimeException,**不可捕獲忽略**,出現即表示程式邏輯錯誤(如遍歷中修改集合),需檢查代碼。
public void remove() {
...
AbstractList.this.remove(lastRet);
...
expectedModCount = modCount; // 同步快照,避免誤判
...
}
Iterator.remove() 除外)。Collection c = new ArrayList(); 換成 LinkedList 或 Vector,其餘代碼完全不用動。Collection c = new ArrayList();
c.add("abc");
c.add("xyz");
for (Iterator it = c.iterator(); it.hasNext(); ) {
String s = (String) it.next();
System.out.println(s);
}