Arrays.asList存在的坑

探讨了在Java开发中使用Arrays.asList()方法将数组转换为集合时的常见陷阱。该方法返回的集合对象不支持add、remove或clear等修改操作,尝试调用这些方法会抛出UnsupportedOperationException。文章深入解析了这一行为的原因,并提供了正确的使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

引语:

阿里巴巴java开发规范说到使用工具类Arrays.asList()方法把数组转换成集合时,不能使用其修改集合相关的方法,它的add/remove/clear方法会抛出UnsupportedOperationException(),我们来看一下为什么会出现这种情况。

问题分析:

我们做个测试

public static void main(String[] args) {
       List<String> list = Arrays.asList("a", "b", "c");
       // list.clear();
       // list.remove("a");
       // list.add("g");
   }

被注释的三行可以分别解开注释,运行后确实出现了规约中所说的异常。我们来看下Arrays.asList()做了什么操作。

public static <T> List<T> asList(T... a) {
       return new ArrayList<>(a);
   }

看上去是个很正常的方法,然而实际上你点进到ArrayList发现,其实ArrayList并不是我们平时用的ArrayList。

private static class ArrayList<E> extends AbstractList<E>
       implements RandomAccess, java.io.Serializable
   {
       private static final long serialVersionUID = -2764017481108945198L;
       private final E[] a;

       ArrayList(E[] array) {
           a = Objects.requireNonNull(array);
       }

       @Override
       public int size() {
           return a.length;
       }

       @Override
       public Object[] toArray() {
           return a.clone();
       }

       @Override
       @SuppressWarnings("unchecked")
       public <T> T[] toArray(T[] a) {
           int size = size();
           if (a.length < size)
               return Arrays.copyOf(this.a, size,
                                    (Class<? extends T[]>) a.getClass());
           System.arraycopy(this.a, 0, a, 0, size);
           if (a.length > size)
               a[size] = null;
           return a;
       }
       // 后面省略了

而是Arrays里面的一个内部类。而且这个内部类没有add,clear,remove方法,所以抛出的异常其实来自于AbstractList。

   public void add(int index, E element) {
       throw new UnsupportedOperationException();
   }

   public E remove(int index) {
      throw new UnsupportedOperationException();
  }

点进去就会发现抛出异常的地方,clear底层也会调用到remove所以也会抛出异常。

总结:

  1. Arrays.asList()不要乱用,底层其实还是数组。

  2. 如果使用了Arrays.asList()的话,最好不要使用其集合的操作方法。

  3. List list = new ArrayList<>(Arrays.asList("a", "b", "c"))可以在外面这样包一层真正的ArrayList。

### Java `Arrays.asList` 常见问题和注意事项 #### 方法签名与返回类型 `Arrays.asList` 是一个便捷的方法,用于创建固定大小的列表。该方法接受可变数量的参数并将其转换为列表对象[^1]。 ```java List<String> list = Arrays.asList("a", "b", "c"); ``` 需要注意的是,此方法返回的对象是一个由数组支持的固定大小的列表实例。因此,尝试修改列表长度的操作将会抛出异常。 #### 修改操作受限 由于返回的列表是基于原始数组构建而来,任何试图改变其结构(即增加或删除元素)的行为都会引发 `UnsupportedOperationException` 异常。然而,可以替换现有索引位置上的元素: ```java list.set(0, "d"); // 正确 // 下面这行会报错 // list.add("e"); // 抛出 UnsupportedOperationException ``` 对于希望获得完全动态特性的场景,则应考虑使用新的 `ArrayList` 构造器来初始化一个新的列表副本: ```java List<String> newList = new ArrayList<>(Arrays.asList("a", "b", "c")); newList.add("d"); // 成功执行 ``` #### 泛型处理不当的风险 当递给 `asList()` 的参数不是基本数据类型的封装类时,在某些情况下可能会遇到意外的结果。特别是如果入单个数组作为参数,那么整个数组会被视为单一元素而非多个独立项组成的序列: ```java String[] array = {"a", "b", "c"}; List<String[]> wrongUsage = Arrays.asList(array); // 列表只有一个元素,即原数组本身 for (Object obj : wrongUsage) { System.out.println(obj.getClass()); // 输出 class [Ljava.lang.String; } ``` 为了得到期望中的字符串列表而不是包含数组本身的列表,应该直接指定泛型参数或将数组展开成离散参数: ```java List<String> correctUsage = Arrays.asList("a", "b", "c"); // 或者通过 Stream API 转换 List<String> streamConversion = Arrays.stream(array).toList(); ``` #### 多线程环境下的行为 考虑到 `Arrays.asList` 返回的列表并非同步实现,所以在多线程环境中共享此类列表之前应当采取额外措施确保线程安全。可以通过 Collections.synchronizedList() 来获取同步版本的列表[^2]。 ```java List<String> threadSafeList = Collections.synchronizedList(Arrays.asList("a", "b", "c")); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值