我们先来看看Arrays.asList。在需要快速将数组转化为列表时,这个方法经常被使用:
List<Integer> statusList = Arrays.asList(1, 2, 3);System.out.println(statusList);  // 输出:[1, 2, 3]
这个方法看似高效,但一旦你试图修改这个列表,比如添加或删除元素:
statusList.add(4);  // 尝试添加一个元素
此时,你将会得到一个java.lang.UnsupportedOperationException异常。
这个问题的根源在于Arrays.asList返回的并不是我们熟悉的java.util.ArrayList,而是一个内部静态类Arrays.ArrayList,它是一个固定大小的列表。

深入源码

让我们看看Arrays.asList的源码:
public static <T> List<T> asList(T... a) {    return new ArrayList<>(a);}
这看起来像是创建了一个ArrayList,但实际上它返回的是一个Arrays内部类的实例:
private static class ArrayList<E> extends AbstractList<E> {    private final E[] a;
    ArrayList(E[] array) {        a = Objects.requireNonNull(array);    }
    // 未实现 add/remove 等修改列表长度的方法}
因为它没有实现修改列表长度的方法,所以会抛出UnsupportedOperationException。

正确的使用方式

为了避免这个问题,推荐使用ArrayList来创建一个可变列表:
List<Integer> mutableList = new ArrayList<>(Arrays.asList(1, 2, 3));mutableList.add(4);  // 现在你可以安心添加元素了System.out.println(mutableList);  // 输出:[1, 2, 3, 4]
这样一来,你就拥有了一个完全可变的列表,随时可以添加或删除元素。

ArrayList.subList的双刃剑

基本用法与问题

接下来,我们看看ArrayList.subList。它可以从列表中获取一个子列表:
List<String> bookList = new ArrayList<>(Arrays.asList("红楼梦", "西游记", "水浒传", "三国演义"));List<String> selectedBooks = bookList.subList(1, 3);System.out.println(selectedBooks);  // 输出:[西游记, 水浒传]
subList返回的不是一个新的列表,而是原列表的一个视图。这意味着,任何对子列表的修改都会反映到原列表上。比如:
selectedBooks.set(1, "封神演义");System.out.println(bookList);  // 输出:[红楼梦, 西游记, 封神演义, 三国演义]
子列表的修改直接影响到了原列表。

常见错误

如果你在子列表存在期间对原列表进行结构性修改(比如添加或删除元素),那么再访问子列表就会抛出ConcurrentModificationException:
 

bookList.add("水经注");System.out.println(selectedBooks);  // 会抛出 ConcurrentModificationException
正确的使用方法
为了避免这个问题,如果你需要一个真正独立的子列表,可以手动创建一个新的ArrayList:
List<String> safeSubList = new ArrayList<>(bookList.subList(1, 3));safeSubList.add("封神演义");System.out.println(safeSubList);  // 输出:[西游记, 水浒传, 封神演义]
这样,子列表的变化不会影响到原列表,反之亦然。

总结与建议

 
  1. 使用Arrays.asList时要小心:不要尝试使用add、remove等方法改变列表大小。如果需要一个可变列表,创建一个新的ArrayList。
  2. 使用subList时需注意:它是原列表的视图,任何修改都会相互影响。如果需要独立的子列表,请创建一个新的ArrayList。
  3. 多加小心,避免常见错误:理解工具背后的实现原理,才能有效地避免使用过程中的“踩雷”。
扫码领红包

微信赞赏支付宝扫码领红包

发表回复

后才能评论