UnsupportedOperationException 的研究

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

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 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3187 引用 • 8213 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • wizardforcel

    看我大 C#:

    int[] arr = {1,2,3,4,5};
    List<int> li = new List<int>(arr);
    
  • eddy

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

  • someone

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

  • someone

    厉害厉害[em04]