P62 99% 开发者都踩过的 List 坑
面试题:Java 里 List 有哪些常见的坑?你踩过哪些?
高频坑清单
坑 1:Arrays.asList 返回的不是 ArrayList
java
List<Integer> list = Arrays.asList(1, 2, 3);
list.add(4); // ❌ UnsupportedOperationExceptionArrays.asList 返回的是内部类 Arrays$ArrayList,长度固定,不能 add/remove;底层数组还和原数组共享。
坑 2:Arrays.asList 包装的是引用类型数组
java
Integer[] arr = {1,2,3};
List<Integer> list = Arrays.asList(arr); // ok
int[] prim = {1,2,3};
List<int[]> list2 = Arrays.asList(prim); // ❌ 得到的是 List<int[]>,长度 1!基本类型数组会被当成一个元素,要用 Arrays.stream(prim).boxed() 处理。
坑 3:subList 的视图语义
java
List<Integer> sub = list.subList(0, 2);
list.add(100); // ❌ sub 再操作时 ConcurrentModificationExceptionsubList 是原列表的视图,原列表结构性修改后,subList 就失效;修改 subList 也会改原列表。
坑 4:遍历时删除元素
java
for (Integer i : list) {
if (i == 1) list.remove(i); // ❌ ConcurrentModificationException
}正确方式:
java
list.removeIf(x -> x == 1);
// 或 Iterator.remove()坑 5:remove 传 int 是按下标删除
java
List<Integer> list = new ArrayList<>(List.of(1,2,3));
list.remove(1); // ❌ 删除的是下标 1(值 2),不是删除元素 1
list.remove(Integer.valueOf(1)); // ✅ 删除元素 1坑 6:toArray 的用法
java
Integer[] arr = list.toArray(new Integer[0]);
// 不要 list.toArray() 强转:会 ClassCastException坑 7:ArrayList 初始容量/扩容
- 默认容量 10,扩容按 1.5 倍(旧容量 + 旧容量 >> 1),批量插入前预估容量避免频繁扩容;
new ArrayList<>(0)与默认构造不同(0 容量,首次 add 才扩到 10)。
坑 8:并发修改
ArrayList非线程安全:多线程 add/remove 会数据错乱;- 用
CopyOnWriteArrayList(读多写少)或Collections.synchronizedList或加锁。
加分点
- 能说出"失败快速(fail-fast)机制":迭代器维护 modCount,结构性修改触发 ConcurrentModificationException;
- 追问"ArrayList vs LinkedList":随机访问 ArrayList O(1),中间插入 LinkedList 理论上 O(n) 但实际都要遍历,别背教条。
一句话总结
List 常见坑:Arrays.asList 不可变、subList 是视图、遍历删除会并发异常、remove(int) 按下标删、toArray 强转报错、ArrayList 非线程安全;记住"快速失败"机制和正确删除姿势基本就能答全。