红和蓝的企业网站设计,xampp系统wordpress,横沥镇网站建设,网站建设应列支什么科目大家好#xff0c;我是静幽水#xff0c;一名大厂全栈程序员#xff0c;今天给大家分享一个案例#xff0c;看似简单。却容易引发惨案。
事情是这样的#xff0c;最近组里来了一个实习生#xff0c;因为项目工作量大#xff0c;人力比较紧张#xff0c;所以就分配了一…大家好我是静幽水一名大厂全栈程序员今天给大家分享一个案例看似简单。却容易引发惨案。
事情是这样的最近组里来了一个实习生因为项目工作量大人力比较紧张所以就分配了一个简单的小需求给他给一个接口增加一个出参返回匹配到的规则编码列表规则编码是数字类型当没有匹配到规则时就返回默认规则编码。他的代码是这样写的
int[] ruleIds new int[roleList.size()];
for (int i 0; i; iroleList.size() ) {ruleIds[i] roleList.get(i).getId;
}ok这里看着还没有问题但是在最后返回结果之前他好像突然想起了如果没有匹配到规则的话要返回一个默认规则Id于是他写下来这段代码。
ListInteger ruleIdList Arrays.asList(ruleIds);
if (ruleIdList.size() 0){ruleIdList.add(defaultId)
}后来对于他的代码我们都觉得比较简单代码review的时候都在review其他同时的比较复杂的代码逻辑也就忽视了他的代码但往往你最轻视的地方就是最容易出问题的地方。就是这个ruleIdList.add()导致在匹配不到规则的场景下程序抛出UnsupportedOperationException异常。而他自测和UT也没有覆盖到这种场景导致这个定时炸弹一直存在到上线之前。还好在上线前的前一天晚上我们发现了这个问题才避免了惨案的发生。
后来我去询问他这样写的动机。为什么上面没有用List而是用的数组他给的解释是因为要放int类型List里面只能放对象我当场吐血。难道不知道自动装箱拆箱吗那后面为啥再转成list呢他说因为前端开发要的list类型。好吧既然事已发生也就没有过多去追问。但是产生这个异常的原因我还是想和大家分享一下。
Arrays.asList()方法是Java中将数组转换为集合的常用方法。它接收一个数组作为参数并返回一个固定大小的List。这个List实际上是Arrays类的私有静态内部类ArrayList的实例。它实现了List接口但是并没有实现List接口中的一些修改集合结构的方法如add()、remove()等。
其实这并不是一种设计上的缺陷而是特意为之目的就是为了提高数组到集合的转换效率避免创建新的ArrayList对象。但是同时也带来了一些限制即不能对返回的List进行修改操作。如果使用修改集合结构的方法例如add()、remove()将会抛出UnsupportedOperationException异常就像上面的代码一样。
为了更好地理解Arrays.asList()方法的局限性我们来看一下它的源码实现。Arrays.asList()方法是在Arrays类中定义的静态方法。
// Arrays类的源码
public static T ListT asList(T... a) {return new ArrayList(a);
}从源码可以看出Arrays.asList()方法接收可变参数而返回的是ArrayList类的实例。这个ArrayList类是Arrays类中的一个内部类实现了List接口。
// Arrays类的内部类ArrayList的源码
private static class ArrayListE extends AbstractListE implements RandomAccess, java.io.Serializable {private final E[] array;ArrayList(E[] array) {if (array null) {throw new NullPointerException();}this.array array;}public E get(int index) {return array[index];}public int size() {return array.length;}// 不支持修改集合结构的方法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();}
}从ArrayList类的源码可以看出它继承了AbstractList类并实现了RandomAccess接口因此支持快速随机访问。但是在ArrayList类中修改集合结构的方法都被重写为抛出UnsupportedOperationException异常从而保证了对返回的List进行修改的操作是不可行的。
除了Arrays.asList()方法还存在其他类似的坑它们在处理集合时也需要注意。
Collections.nCopies()
Collections.nCopies()方法用于创建一个指定元素重复多次的List。这个List同样是固定大小的不能进行修改操作。
ListString list Collections.nCopies(3, apple);
list.add(banana); // 抛出UnsupportedOperationException异常原理和Arrays.asList()类似Collections.nCopies()方法返回的是一个AbstractList的实例不支持修改集合结构的操作。
Arrays.asList()的嵌套问题
Arrays.asList()方法还存在一个嵌套的问题。如果使用Arrays.asList()方法将一个二维数组转换为List会得到一个List的嵌套结构此时对内层的List进行修改同样会抛出UnsupportedOperationException异常。
String[][] array2D { { apple, banana }, { orange, grape } };
ListListString nestedList Arrays.asList(array2D);
nestedList.get(0).add(kiwi); // 抛出UnsupportedOperationException异常原因是这个嵌套的List中的元素仍然是固定大小的List。
这种设计是为了提高效率和节省内存开销。在转换数组到集合时能直接使用Arrays.asList()方法的时候它是非常方便的。但是当需要对集合进行修改操作时应该创建一个新的ArrayList对象并使用addAll()方法将数组元素添加进去以避免UnsupportedOperationException异常的发生。
代码示例
String[] array { apple, banana, orange };
ListString list new ArrayList();
Collections.addAll(list, array);
list.add(grape); // 正常添加元素到集合中或者如下
ListString Ids new ArrayList(Arrays.asList(array));
Ids.add(id);Collections.unmodifiableList()方法的不可修改特性
Collections.unmodifiableList()方法返回的是一个不可修改的List。它采用了装饰器模式对原始List进行了封装重写了修改集合结构的方法并抛出UnsupportedOperationException异常。
ListString originalList new ArrayList();
originalList.add(apple);
ListString unmodifiableList Collections.unmodifiableList(originalList);
unmodifiableList.add(banana); // 抛出UnsupportedOperationException异常总结 在使用Arrays.asList()方法将数组转换为集合时注意其局限性。返回的List是一个固定大小的List不支持修改集合结构的方法。类似的坑还有Collections.nCopies()方法和Arrays.asList()的嵌套问题它们同样需要注意不能对返回的集合进行修改操作。