在调试程序的时候发现一个奇怪的问题,代码都是写过的很常见的代码,但是看日志会报错,报错信息如下:
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。
最后想说的是今天探究这个异常,如果只是上面的示例代码,大家肯定不会犯错,但是如果是接口调接口,模块调模块,就很难发现这样的问题,希望对大家有帮助。