keySet调用addAll报UnsupportedOperationException

问题背景

业务中想要将一个set中的元素添加到一个keySet中,以为可以类似List一样,调用java.util.Collection#addAll(Collection<? extends E> c),如

1
2
// 将一个list的元素加到另一个list中
list2.addAll(list1);

于是写成

1
2
3
4
// 从map获取keySet
Set<String> videoWxhSet = resolutionMap.keySet();
// 将一个set加到另一个set中
videoWxhSet.addAll(picWxhSet);

编译没有问题,运行报错了,显示该操作不被支持

Caused by: java.lang.UnsupportedOperationException
at java.util.AbstractCollection.add(AbstractCollection.java:262)
at java.util.AbstractCollection.addAll(AbstractCollection.java:344)

原因

源码分析

keySet方法返回了一个HashMap.KeySet对象,是HashMap的内部类。

image-20230220163727710

keySet方法并未实现add/addAll等方法

image-20230220163644153

Collection#addAll方法在未实现的情况下调用会抛出UnsupportedOperationException异常。

image-20230220165556245

查看HashMap源码里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

简单翻译下

keySet返回的是map中所有的key,对map的修改会影响到keySet,反之对keySet的修改也会影响到map。所以set支持元素移除,但不支持元素添加

验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();

map.put("大韩", "a");
map.put("民国","a");
map.put("万岁","c");
System.out.println(map); // {民国=b, 万岁=c, 大韩=a}

Set<String> keySet = map.keySet();
System.out.println(keySet); // [民国, 万岁, 大韩]

// 对map的增删,会影响到set
map.put("朝鲜", "d");
map.remove("大韩");
System.out.println(map); // {民国=b, 朝鲜=d, 万岁=c}
System.out.println(keySet); // [民国, 朝鲜, 万岁]

// 对 keySet的操作,也会影响到map
keySet.remove("民国");
System.out.println(map); // {朝鲜=d, 万岁=c}
System.out.println(keySet); // [朝鲜, 万岁]

}

可以看到,对keySet的修改会同步到map。所以对keySet的添加是有问题的,因为添加的key在map里没有对应的value


解决方案

重新new HashSet(),将两个set丢进去即可

1
2
3
HashSet<String> allWxhSet = new HashSet<>();
allWxhSet.addAll(picWxhSet);
allWxhSet.addAll(videoWxhSet);
文章作者: SongGT
文章链接: http://www.songguangtao.xyz/2022/07/28/3.keySet调用addAll报错/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 SongGuangtao's Blog
大哥大嫂[微信打赏]
过年好[支付宝打赏]