1. 场景还原
最近在设计的一个类中,有成员属性
Map<String, List<String>> headers = new HashMap<>();
在实际使用过程中,发现对该属性的 value
进行 add()
操作会抛出异常 UnsupportedOperationException
。感觉略有奇怪,于是便开始研究。
2. 什么时候会抛出异常
使用这段代码
Map<String, List<String>> headers = new HashMap<>();
headers.put("zjh", Arrays.asList("123"));
headers.get("zjh").add("456");
会抛出异常。
而使用这段代码
Map<String, List<String>> headers = new HashMap<>();
String[] str = {"123"};
headers.put("zjh", new ArrayList<>(Arrays.asList(str)));
headers.get("zjh").add("000");
不会抛出异常。
而在前文所述中,我设计的类内就是使用第一段代码的形式才抛出了异常。
以此,我便猜测是 Arrays.asList()
有问题。
3. 进一步研究
使用这段代码
List<String> lists = Arrays.asList("123","456","789","000");
lists.add("999");
会抛出异常。
查看 Arrays.asList
的源码,发现其返回的是对象属性是 ArrayList
感觉没毛病啊!
之后再往下看
原来是它自定义了一个内部类,类名是 ArrayList!
查看这个父类 AbstractList
的情况
其内部的 add
实现为
public boolean add(E e) {
add(size(), e);
return true;
}
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
一切真相大白,Arrays.asList
方法返回的 List
对象内部没有实现 add 方法!
4. 更多的实验
其实,Arrays.asList
方法的返回就是对传入参数数组的引用。对数组进行修改也会导致 Arrays.asList
的返回值发生改变。
如下代码:
String[] str = {"123","456","789","000"};
List<String> lists = Arrays.asList(str);
str[1] = "9999";
System.out.println(str[1]); // 9999
System.out.println(lists); // [123, 9999, 789, 000]
这也可以解释为什么 Arrays.asList
的返回值无法 add
或者 remove
。如果允许其可以变长,那么原始的数组内容应该如何修改呢?所以最后 Java 的开发人员便使其返回一个不可修改长度的 List
。
以上所述在源码里也能体现出来,更具体的大家可以参阅 Arrays
这个类的源码!
5. 解决方案
我的建议是如果对 List 内部元素会有增删的操作的话,慎用 Arrays.asList
方法,如果非要用,可以绕一绕。
例如:
List<String> lists = new ArrayList<>(Arrays.asList("111", "222", "333"));
如此生成的 list,可变长!
代码稍微长一点,可以使用循环来给 List
内增加元素。
当然,我只是提供了最简单的解决方案,具体方案要放在具体项目中选择使用。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于