"1. 场景还原 最近在设计的一个类中,有成员属性 Map> headers = new HashMap<>(); 在实际使用过程中,发现对该属性的value进行add()操作会抛出异常UnsupportedOperationException。感觉略有奇怪,于是便开始研究。 2. 什么时候会抛出异常 .."

UnsupportedOperationException 的研究

本贴最后更新于 767 天前,其中的信息可能已经时移俗易

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 原来是它自定义了一个内部类,类名是 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内增加元素。 当然,我只是提供了最简单的解决方案,具体方案要放在具体项目中选择使用。

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    2153 引用 • 7264 回帖 • 1052 关注
感谢    关注    收藏    赞同    反对    举报    分享
4 回帖    
请输入回帖内容...
  • wizardforcel      

    看我大 C#:

    int[] arr = {1,2,3,4,5};
    List<int> li = new List<int>(arr);
    
    感谢    赞同    反对    举报    分享       回复
  • eddy    

    Arrays.asList(“123”) 返回的 list 实例只可读,不可写。写接口没有实现·······

    感谢    赞同    反对    举报    分享       回复
  • zjhch123 API      

    应该说是不可改变长度吧…改变元素的值是可以实现的

    感谢    赞同    反对    举报    分享       回复
  • zjhch123 API      

    厉害厉害

    感谢    赞同    反对    举报    分享       回复