项目场景
这是一位朋友给我分享的实际线上问题,看似简单却害了项目再次造出一个bug来。
场景:线上环境中,需要查询某某业务数据,条件是状态,之前产品只要求查两个状态的,但现在让他再多查一个状态的。
自信满满的他,以为就加个状态,肯定没问题的。
在代码中,这位朋友用到了Arrays工具类。
写法如下:
List<Integer> statusList= Arrays.asList(0,1);
这里看起来没问题。
第一种想到的就是直接加个状态就搞定了。
List<Integer> statusList= Arrays.asList(0,1,2);
但是,他定义的statusList在方法也有个查询用到了!
为了不影响其他部分代码,于是,他就是这么干的:
List<Integer> statusList= Arrays.asList(0,1);
statusList.add(2);
就加了一行代码,非常非常简单,没有任何逻辑。
并且,本地编译也没问题,自信满满的,和领导说,改好了,可以上线了。
可是,一上线就大量报错:
Exception in thread "main" java.lang.UnsupportedOperationExceptionat java.base/java.util.AbstractList.add(AbstractList.java:153)at java.base/java.util.AbstractList.add(AbstractList.java:111)
懵了呀,这!怎么可能报错,我就往List中加了一条数据而已。
哎,今年的年终奖估计是无望了,可是自己却觉得自己很无辜。
问题分析
分析上述代码:
List<Integer> statusList= Arrays.asList(0,1);
statusList.add(2);
进入asList方法:
public static <T> List<T> asList(T... a) {return new ArrayList<>(a);}
返回了一个ArrayList,凭我们的经验,向这个list里面add一个元素肯定没问题。
但是,为什么会报错呢?
其实,这里的ArrayList,并非我们平常说的ArrayList。
这里的ArrayList是Arrays中内部类。
ArrayList的基本定义:
private static class ArrayList<E> extends AbstractList<E>implements RandomAccess, java.io.Serializable {// ......}
使用快捷键Alt+7
查看内部类ArrayList主要包含哪些方法?
到这里,我们可以发现,ArrayList里完全没有add方法,也就是说这里的内部类ArrayList是不支持add的。
再回到上面说的报错异常:UnsupportedOperationException
AbstractList中add报错的
public void add(int index, E element) {throw new UnsupportedOperationException();}
总结
Arrays.asList返回的List是Arrays中内部类。该内部类ArrayList继承了AbstractList但未重写
父抽象类里面的add和remove方法。
因此,调用add、remove方法实际上是调用了父类AbstractList中的方法。
查看AbstractList发现这几个都未具体实现,直接返回了不支持操作异常即UnsupportedOperationException异常!
public void add(int index, E element) {throw new UnsupportedOperationException();}public E remove(int index) {throw new UnsupportedOperationException();}