
为什么 Collections.swap 不能交换 Arrays.asList 返回的列表?
因为 Arrays.asList 返回的是一个固定大小的、不支持结构性修改的列表实现(Arrays$ArrayList),而 Collections.swap 内部会尝试调用 set 方法——这在该实现中会抛出 UnsupportedOperationException。
- 常见错误现象:
Exception in thread "main" java.lang.UnsupportedOperationException - 使用场景:你用
String[] arr = {"a","b","c"};转成List后直接 swap,就踩坑了 - 解决办法:包装一层可变列表,比如
new ArrayList(Arrays.asList(...)) - 性能影响:多一次构造,但只在初始化时发生,无运行时开销
Collections.swap 的索引越界行为和安全边界
它不会做任何索引检查,传入负数或超出 list.size() 的索引,会在内部调用 get 或 set 时直接抛出 IndexOutOfBoundsException —— 和你手动 get/set 一样。
- 容易踩的坑:误以为 swap 会自动校验或静默忽略非法索引
- 建议做法:调用前自己判断
i >= 0 && i = 0 && j - 参数差异:两个索引顺序无关,
swap(list, 0, 2)和swap(list, 2, 0)效果完全相同
替代方案:手写 swap 时要注意泛型擦除陷阱
如果你绕过 Collections.swap 自己写,比如用临时变量 + set,得小心泛型类型安全问题。尤其在方法签名里用了通配符或原始类型时,编译器可能放行但运行时报错。
- 典型错误代码:
List> list = new ArrayList<string>(); swap(list, 0, 1);</string>—— 编译失败,因为?不允许set - 正确写法:确保列表是具体泛型类型,如
List<string></string>;或用Object临时变量(但丢失类型信息) - 示例安全写法:
public static <T> void swap(List<T> list, int i, int j) {<br> T tmp = list.get(i);<br> list.set(i, list.get(j));<br> list.set(j, tmp);<br>}
不可变列表、并发列表等特殊实现的兼容性
Collections.swap 本质依赖 get + set,所以只要列表实现了这两个方法且允许修改,它就能工作;否则就会失败。
立即学习“Java免费学习笔记(深入)”;
- 明确不支持:所有
Collections.unmodifiable*系列返回的视图、List.of()(Java 9+)、Guava 的ImmutableList - 需注意并发安全:对
CopyOnWriteArrayList可以用,但每次set都触发复制,高频 swap 会显著拖慢性能 - 推荐判断方式:看文档是否声明 “supports the set operation” —— 这是 JDK Javadoc 中的明确判定依据










