Skip to content

P62 99% 开发者都踩过的 List 坑 ​

面试题:Java 里 List 有哪些常见的坑?你踩过哪些?

高频坑清单 ​

坑 1:Arrays.asList 返回的不是 ArrayList ​

java
List<Integer> list = Arrays.asList(1, 2, 3);
list.add(4);  // ❌ UnsupportedOperationException

Arrays.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 再操作时 ConcurrentModificationException

subList 是原列表的视图,原列表结构性修改后,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 非线程安全;记住"快速失败"机制和正确删除姿势基本就能答全。

基于 VitePress 重建