開發者調用 list.remove() 拋出 NullPointerException,疑惑:「List 已實例化為什麼還會空指針?」
| 概念 | 含義 | 示例 |
|---|---|---|
| List 實例化 | 引用指向有效 ArrayList 對象 | List |
| List 為空 | list.size() == 0,無元素 | list.isEmpty() == true |
| 元素為 null | 列表包含 null 引用 | list.add(null); list.get(0) == null |
List list = null; // 未實例化
list.remove(0); // NPE:list 為 null
List list = new ArrayList<>();
list.add(null);
list.remove(null); // 正常返回 true,不拋 NPE
// 但如果是並發集合或自定義實現
ConcurrentLinkedQueue q = new ConcurrentLinkedQueue<>();
q.add(null);
q.remove(null); // 部分實現可能拋 NPE
List list = new ArrayList<>();
list.remove(0); // IndexOutOfBoundsException,非 NPE
System.out.println(list)Collections.synchronizedList 或 CopyOnWriteArrayListlist.remove(nullObj) 而 nullObj 為 null 導致內部 NPE(極少見)| 集合類型 | remove(Object) | remove(int index) |
|---|---|---|
| ArrayList | 移除首個匹配元素,含 null | 索引越界拋 IOOBE |
| LinkedList | 同 ArrayList | 同 |
| Vector | 同步版同 ArrayList | 同 |
| CopyOnWriteArrayList | 同 | 同 |
// 安全移除模式
public boolean safeRemove(List list, String element) {
if (list == null) return false; // 1. 檢查引用
if (element == null) { // 2. 處理 null 元素
return list.remove(null); // 明確語義
}
return list.remove(element); // 3. 正常移除
}
// 並發環境
List safeList = new CopyOnWriteArrayList<>();
// 或
List syncList = Collections.synchronizedList(new ArrayList<>());
synchronized(syncList) {
syncList.remove(element);
}
// 異常堆棧定位
try {
list.remove(obj);
} catch (NullPointerException e) {
System.err.println("list=" + list);
System.err.println("obj=" + obj);
e.printStackTrace();
}
// 斷點條件
// IDE 設置條件斷點:list == null
list.remove() 拋 NPE,99% 是 list 引用本身為 null。實例化只創建了容器對象,不保證引用不為 null、不保證有元素、不保證線程安全。排查核心:驗證引用非空 → 驗證實例化路徑必經 → 驗證線程安全。養成「聲明即初始化、參數非空斷言、並發用安全容器」習慣,從源頭消滅此類低級錯誤。