UnsupportedOperationException深层探究

在调试程序时遇到UnsupportedOperationException,原因是使用Collections.singletonList创建的List无法执行set方法,因为SingletonList没有实现这个方法。文章通过代码示例解释了ArrayList和SingletonList的区别,以及在高并发场景下考虑性能的重要性。

在调试程序的时候发现一个奇怪的问题,代码都是写过的很常见的代码,但是看日志会报错,报错信息如下:

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.AbstractList.set(AbstractList.java:132)

跟到AbstractList的源码里面,发现其确实就是抛出的这个异常:

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

为什么会走到抽象类AbstractList的这个set方法中,而不是在具体的子类的该方法中,debug代码发现子类并不是ArrayList,请看:

原来是SingletonList,这个是通过Collections的下面方法实例化的,但是其并没有提供set()方法

    public static <T> List<T> singletonList(T o) {
        return new SingletonList<>(o);
    }

如果是ArrayList就有此方法:

   public E set(int index, E element) {
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }

因此只要是通过Collections的SingletonList创建的list,就无法使用set(int index, E element)方法,最终会走到父类AbstractList中的set方法中,最终导致抛出异常。

先来看看错误代码是如何写的:

实体类

public class People {
    List<MyTask> list;

    public List<MyTask> getList() {
        return list;
    }

    public void setList(List<MyTask> list) {
        this.list = list;
    }
}

测试类

public static void main(String[] args) {
MyTask myTask = new MyTask(1, 1, 1);
   MyTask[] arr = new MyTask[]{myTask};
   People people = new People();
   List<MyTask> list = Collections.singletonList(myTask);
   people.setList(list);
   list.get(0).setTelNum(98);
   people.getList().set(0, list.get(0));
   System.out.println(people.getList().get(0));
}

上面代码的第5行做下面的替换即可:

List<MyTask> list = new ArrayList<>();
list.add(myTask);

有的同学会说了,平常写代码都是用的new来初始化对象,为什么要整那么复杂用到Collections去初始化,如果做毕设或者系统仅仅是普通的管理系统确实不用考虑那么多,因为资源是富足的,当是做高并发系统或者资源的使用率非常高,就要考虑性能问题。

最后说下对于List的采用new的方式或者Collections的方式有什么不同吧。

ArrayList的实质是一个数组,JDK默认给的是10,就是只要一初始化,还没有赋值,就开辟了10个元素的内存空间。但是Collections.singletonList()方式是初始化一个有且仅有一个元素的list。

最后想说的是今天探究这个异常,如果只是上面的示例代码,大家肯定不会犯错,但是如果是接口调接口,模块调模块,就很难发现这样的问题,希望对大家有帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值