调用Set.add(All)出现java.lang.UnsupportedOperationException异常原因以及解决方法

本文通过示例代码详细解析了Java中使用Map的keySet方法时常见的错误及原因,介绍了如何正确地从Map中获取键集合,并对集合进行修改。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一个初学者很常见的错误,因为困扰了我有一些时间,所以就写在这里备忘并希望帮助其他初学java的人。

首先看一段代码:

    Map<String, Integer> map = new HashMap<>();
    map.put("a", 0);
    map.put("b", 1);
    map.put("c", 2);
		 
    Set<String> set = map.keySet();
    set.add("w");

  或者把set操作改成这个样子:

    Set<String> set = map.keySet();		 
    Set<String> tmp = new HashSet<>();
    tmp.add("w");
    set.addAll(tmp);

 这两段代码看起来没什么问题,不过实际运行会出现一个异常:

Exception in thread "main" java.lang.UnsupportedOperationException
	at java.util.AbstractCollection.add(Unknown Source)
	at java.util.AbstractCollection.addAll(Unknown Source)



Map.keySet理论上来讲是返回一个Set集合,那么向里面添加一个元素为什么会报错呢?原因其实很简单,不过初学者真心想不到,我们先看一下Map.keySet的帮助文档:

Set<String> java.util.Map.keySet()

keySet
Set<K> keySet()

Returns a Set view of the keys contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa. If the map is modified while an iteration over the set is in progress (except through the iterator's own remove operation), the results of the iteration are undefined. The set supports element removal, which removes the corresponding mapping from the map, via the Iterator.remove, Set.remove, removeAll, retainAll, and clear operations. It does not support the add or addAll operations.
Returns:a set view of the keys contained in this map

注意说明的最后一句话“ The set supports element removal, which removes the corresponding mapping from the map, via the Iterator.remove, Set.remove, removeAll, retainAll, and clear operations. It does not support the add or addAll operations.”可见Map.keySet返回的Set对象仅仅支持元素的移除,并不支持增改!所以当增加元素时才会爆出这个异常。



解决方法:

其实也比较简单,我们利用构造函数将Map.keySet返回的集合拷贝一份就好了:

    //Set<String> set = map.keySet();	
    Set<String> set = new HashSet<>(map.keySet());	



<think>我们正在处理的是 `java.lang.UnsupportedOperationException` 错误。根据引用内容,这个异常通常发生在尝试修改一个不可变的集合时。具体来说,当我们使用 `Arrays.asList()` 方法将数组转换为列表后,得到的列表是固定大小的(不支持添加或删除操作),调用 `add()` 或 `remove()` 等方法就会抛出此异常。 ### 错误原因分析 1. **不可变集合操作**:通过 `Arrays.asList()` 返回的列表是 `Arrays` 的内部类 `ArrayList`,它继承自 `AbstractList` 但没有重写 `add()` 和 `remove()` 等方法。因此,当调用这些方法时,实际上调用的是 `AbstractList` 中的默认实现,即直接抛出 `UnsupportedOperationException`[^4][^5]。 2. **常见触发场景**: - 尝试向 `Arrays.asList()` 返回的列表中添加元素(`add()` 方法) - 尝试从中删除元素(`remove()` 方法) - 其他修改操作(如 `clear()`) ### 解决方案 #### 方法1:创建新的 `ArrayList` 对象 将 `Arrays.asList()` 返回的列表作为参数传递给一个新的 `ArrayList` 对象,这样得到的列表就是可变的。 ```java List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c")); list.add("d"); // 现在可以正常添加 ``` #### 方法2:使用 Java 8 的 Stream API(适用于 Java 8 及以上) ```java List<String> list = Stream.of("a", "b", "c").collect(Collectors.toList()); list.add("d"); // 正常 ``` #### 方法3:使用 Collections 工具类(不常用) ```java List<String> list = new ArrayList<>(); Collections.addAll(list, "a", "b", "c"); list.add("d"); // 正常 ``` ### 示例代码对比 #### 错误代码 ```java List<String> list = Arrays.asList("a", "b", "c"); list.add("d"); // 抛出 UnsupportedOperationException ``` #### 正确代码 ```java // 方法1 List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c")); list.add("d"); // 成功 // 方法2(Java 8+) List<String> list = new ArrayList<>(Stream.of("a", "b", "c").collect(Collectors.toList())); list.add("d"); // 方法3 List<String> list = new ArrayList<>(); Collections.addAll(list, "a", "b", "c"); list.add("d"); ``` ### 关键点总结 | **操作** | **Arrays.asList() 返回的列表** | **new ArrayList<>() 创建的列表** | |------------------|--------------------------------|----------------------------------| | 支持添加元素 | ❌ 抛出异常 | ✅ 允许 | | 支持删除元素 | ❌ 抛出异常 | ✅ 允许 | | 支持修改元素 | ✅ (通过 `set` 方法) | ✅ 允许 | | 数据结构是否可变 | 固定大小(不可变) | 动态大小(可变) | > **注意**:`Arrays.asList()` 返回的列表虽然不可变,但支持通过 `set(index, element)` 修改已有位置的元素[^5]。 --- §§相关问题§§ 1. 如何正确初始化一个可变的字符串列表? 2. Java 中哪些集合操作会抛出 `UnsupportedOperationException`? 3. 如何将数组转换为可修改的列表? 4. Java 集合框架中哪些集合是不可变的? [^1]: [java.lang.UnsupportedOperationException解决方法【转】](引用链接1) [^2]: [java.lang.UnsupportedOperationException问题分析及解决](引用链接2) [^3]: [java.lang.UnsupportedOperationException解决方法](引用链接3) [^4]: [报错:java.lang.UnsupportedOperationException 原因](引用链接4) [^5]: [java.lang.UnsupportedOperationException报错如何解决](引用链接5)</think>### 分析 `java.lang.UnsupportedOperationException` 报错原因解决方案 #### **根本原因分析** 该异常通常发生在尝试修改**不可变集合**时,核心原因是底层集合实现未重写修改方法(如 `add()`, `remove()` 等)。具体场景: 1. **使用 `Arrays.asList()` 创建的集合**(最常见原因) ```java List<String> list = Arrays.asList("A", "B", "C"); // 返回 Arrays$ArrayList list.add("D"); // 抛出 UnsupportedOperationException ``` - `Arrays.asList()` 返回的是 `Arrays` 内部类 `ArrayList`,它继承自 `AbstractList` 但**未重写 `add()/remove()` 方法**[^4][^5] - `AbstractList` 的默认实现是直接抛出异常: ```java public void add(int index, E element) { throw new UnsupportedOperationException(); } ``` 2. **其他不可变集合操作** - 通过 `Collections.unmodifiableList()` 创建的只读集合 - `List.of()` 创建的不可变集合(Java 9+) - 尝试修改 `Map.keySet()` 或 `Map.values()` 等视图集合 --- #### **解决方案** ##### 方案1:创建真正的可变集合(推荐) ```java // 使用标准 ArrayList 包装 List<String> mutableList = new ArrayList<>(Arrays.asList("A", "B", "C")); mutableList.add("D"); // ✅ 正常执行 ``` ##### 方案2:使用 Java 8+ 的流式 API ```java List<String> list = Stream.of("A", "B", "C") .collect(Collectors.toList()); // 返回可变 ArrayList list.add("D"); // ✅ ``` ##### 方案3:需要修改集合视图时 ```java Map<String, Integer> map = new HashMap<>(); map.put("A", 1); // 错误:直接修改 keySet 视图 // Set<String> keys = map.keySet(); // keys.remove("A"); // ❌ 抛出异常 // 正确:创建新集合 Set<String> keys = new HashSet<>(map.keySet()); keys.remove("A"); // ✅ ``` --- #### **关键区别:两种 ArrayList** | **特性** | `java.util.ArrayList` | `Arrays$ArrayList` (内部类) | |------------------------|-------------------------------|----------------------------------| | 所在包 | `java.util` | `java.util.Arrays` | | 是否可修改 | ✅ 支持 add/remove | ❌ 固定大小 | | 继承关系 | 重写 `AbstractList` 所有方法 | 未重写 `add()/remove()` 方法[^5] | | 内存结构 | 动态数组 | 直接包装原始数组 | | 适用场景 | 常规可变集合 | 临时只读视图 | --- #### **最佳实践** 1. **明确集合的可变性**: ```java // 只读集合(明确声明) List<String> readOnly = Collections.unmodifiableList(Arrays.asList("A", "B")); // 可变集合(显式创建) List<String> mutable = new ArrayList<>(readOnly); ``` 2. **避免直接操作**: - 不要直接修改 `Arrays.asList()`, `List.of()`, `Collections.singletonList()` 的返回值 - 需要修改时先通过构造函数复制 3. **使用现代 API**(Java 9+): ```java List<String> mutable = new ArrayList<>(List.of("A", "B")); // 安全复制 ``` > 📌 **调试提示**:遇到此异常时,检查集合的运行时类型(`list.getClass().getName()`),若为 `java.util.Arrays$ArrayList` 则说明问题根源在此[^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值