Arrays.asList陷阱揭秘:集合操作禁地,小心踩坑!

大家好,我是Hunk。

今天实习生阿豪一脸懵逼的找到我说遇到了一个诡异问题,他说自己创建好的集合在执行添加元素操作时抛出了UnsupportedOperationException异常。有经验的人光听到这个异常就大概知道是踩坑了。

接下来我们按照他所创建集合的方式,并结合代码示例,来具体讲解一下为啥他的操作不能正常执行,代码示例如下所示。

public static void main(String[] args) {
    // 通过Arrays.asList,将数组转成集合
    List<String> list = Arrays.asList("Lucy""Lily");
    list.add("Tom");
}

运行main方法后,异常如下所示。

Exception in thread "main" java.lang.UnsupportedOperationException
 at java.util.AbstractList.add(AbstractList.java:148)
 at java.util.AbstractList.add(AbstractList.java:108)
 at com.hunk.Test.main(Test.java:11)

之所以会抛出异常就是因为这个Arrays.asList()方法导致的,不光执行添加元素操作会抛出异常,像list.clear()list.remove()这些涉及修改集合的方法也会抛出相同的异常。

接下来我们进入Arrays.asList()方法,看看它具体都做了些啥操作。

@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}

乍一看,好像也没啥问题,这不就是new出来一个ArrayList吗。很多人跟到了这一步就觉得没啥往下看的必要了。

这个时候特别想说一句非常经典的话:你以为你以为的就是你以为的?

跟着继续往下走,当点进ArrayList的时候,咦~~~好像发现问题了!这个new出来的ArrayList并不是我们平时用的java.util.ArrayList,而是Arrays里面的一个内部类。

private static class ArrayList<Eextends AbstractList<E>
        implements RandomAccessjava.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;
    }

    …………
}

到这大家应该明白是咋回事了吧。然后我们再具体看下这个内部类,里面并没有我们前面所说的诸如add()clear()remove()等方法。之所以执行上述方法会抛出UnsupportedOperationException异常,是因为它继承的AbstractList抛出的。

public abstract class AbstractList<Eextends AbstractCollection<Eimplements List<E{
    /**
     * Sole constructor.  (For invocation by subclass constructors, typically implicit.)
     */

    protected AbstractList() {
    }
    
    public boolean add(E e) {
        add(size(), e);
        return true;
    }
    
    public E set(int index, E element) {
        throw new UnsupportedOperationException();
    }
    
    public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }
    
    public E remove(int index) {
        throw new UnsupportedOperationException();
    }
    
    public void clear() {
        removeRange(0, size());
    }
    ……
}

可以看到在AbstractList中涉及修改集合的操作,最终都会抛出异常。

其实这个问题在阿里的《Java开发手册》中也有明确的约定,而且是强制性的,如下所示。

Arrays.asList陷阱揭秘:集合操作禁地,小心踩坑!


至此,阿豪的问题就彻底分析清楚了,吃一堑长一智,以后就不要再往坑里跳了!

Arrays.asList陷阱揭秘:集合操作禁地,小心踩坑!

END

原文始发于微信公众号(Java浩窍门):Arrays.asList陷阱揭秘:集合操作禁地,小心踩坑!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/244520.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!