Arrays
Arrays 是数组对象进行操作的工具类,其中含有对数组的排序、查找、对比、拷贝等操作。通过工具类,我们还可以将数组转换成集合。
数组和集合都是 Java 中用来存储数据的,数组性质单一,方便使用;集合通过泛型达到类型安全,功能强大,而且两者之间还可以进行互相转换。毕竟两者之间有明显不同,在进行转换的时候,如果稍不注意就会出错。
转换时分为两种情况:
- 数组转换成集合
- 集合转换成数组
错误:java.lang.UnsupportedOperationException
举个平时容易遇错的问题:将数组转换成集合是用Arrays.asList()
方法。转换后的集合,如果要使用 add/remove/clear ,那么会抛出java.lang.UnsupportedOperationException
异常。
String[] strings = {"ab","cd","ef"};
List<String> list = Arrays.asList(strings);
// 三行语句都编译通过,但都抛出运行时异常
list.add("gh");
list.remove("cd");
list.clear();
// set修改成功,将第一位改成"aa"
list.set(0,"aa");
// 遍历出做对比
for (String string : strings) {
System.out.print(string + ",");
}
System.out.println();
System.out.println(list);
运行结果为:
// 发现原数组也别修改了
aa,cd,ef,
[aa, cd, ef]
通过上段代码可以发现,我们可以使用 set 方法,而且不会抛出运行时异常,在修改集合List中值的同时,原数组上的值也跟着被修改了。因为Arrays.asList()
采用的是适配器模式,在后台操作的数据仍是原有的数据,set方法也就是间接对数组里的值进行修改。返回值为修改前的旧值。
另外还发现,只要是修改元素个数的操作,就会抛出java.lang.UnsupportedOperationException
异常。
查看源码
我们再进一步了解 asList 方法它具体返回的到底什么对象,进入源码查看:
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
从源码中可发现,它返回的是一个 ArrayList 对象。
那为什么它不能像ArrayList那样正常的对数据操作?继续点下去:
惊人的发现,原来在 Arryas 中竟然定义了一个 ArrayList 的内部类,它与平时 Arrays 同包下的 ArrayList 并不是同一个类!难怪会有功能限制。
简单的翻了下不到100行的内部类源码,除了有看到了 set 修改方法外,却怎么也找不到能修改集合个数的相关方法,那么是谁抛出了java.lang.UnsupportedOperationException
异常?答案是内部类的父类 AbstractList。
源码:(注解太长了,就不截图了)摘取关键源码
public abstract class AbstractList<E> extends AbstractCollection<E>
implements List<E> {
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
public E remove(int index) {
throw new UnsupportedOperationException();
}
// clear()方法在内部转了一圈还是调用remove方法,依然抛出
public void clear() {
removeRange(0, size());
}
所以在业务上,如果以这样的方式返回一个 List,即使在大部分情况下都只做读操作,但只要有一个写入修改操作,那么就会出错引发故障。
解决问题
当然,这也不是没有解决的办法,可以将Arrays.asList()
返回的 List 作为参数创建一个新的 ArrayList。
String[] strings = {"ab","cd","ef"};
List<String> list = new ArrayList<>(Arrays.asList(strings));
这样一来,就可以正常使用了。
愿世上永无Bug