ArrayList的subList返回原列表的视图,左闭右开截取、共享存储;读取安全,修改影响原列表;需独立副本时须显式new ArrayList()复制。

ArrayList 的 subList 方法用于快速获取原列表中一段连续元素的“视图”,它不复制数据,而是共享底层存储——用得对很轻量,用错就容易出联动或异常。
怎么截取:左闭右开,索引要合法
调用格式为 list.subList(fromIndex, toIndex),其中:
-
fromIndex 是起始位置(包含),toIndex 是结束位置(不包含),即区间
[fromIndex, toIndex); - 必须满足
0 ≤ fromIndex ≤ toIndex ≤ list.size(),否则抛IndexOutOfBoundsException; - 空列表调用
subList(0, 0)合法,返回空视图;但subList(0, 1)会直接失败。
例如:list = ["a", "b", "c", "d"],执行 list.subList(1, 3) 得到 ["b", "c"]。
怎么使用:读取安全,修改需谨慎
subList 返回的是视图,不是新列表:
- 调用
get()、size()、遍历等只读操作完全安全,且无额外内存开销; - 调用
set(i, e)会直接改原列表对应位置的元素; - 调用
add()或remove()会同步影响原列表(比如subList.add("x")实际在原列表插入,可能改变后续索引); - 若原列表在 subList 创建后发生结构性修改(如
add()、remove()、clear()),再访问该 subList 很可能触发ConcurrentModificationException。
怎么避免踩坑:需要独立副本时必须显式创建
如果业务要求子列表与原列表互不影响(比如要排序、删减、长期缓存),就不能直接用 subList,而要立即复制:
- 最常用:
new ArrayList(list.subList(from, to)); - JDK 8+ 可选:
list.subList(from, to).stream().collect(Collectors.toList()); - 注意:
Collections.unmodifiableList()或Arrays.asList()包装 subList 仍无法隔离,因为它们包装的还是那个视图。
性能与替代建议
不同底层实现表现差异大:
- ArrayList.subList 创建是 O(1),后续
get()也是 O(1); - LinkedList.subList 虽然也返回视图,但每次
get(i)都要遍历链表,性能差,不推荐用于随机访问; - 如果只是临时切片读取,用
Stream.skip(m).limit(n)更语义清晰、无副作用; - 高频使用场景可封装工具方法,如
safeSubList(list, from, to)内部自动 new ArrayList,减少误用风险。


















