java.lang.UnsupportedOperationException: null 异常原因

1. 不可变集合的修改操作

1.1 Arrays.asList 返回的 List

List<String> list = Arrays.asList("a", "b");
list.add("c");      // UnsupportedOperationException
list.remove(0);     // UnsupportedOperationException
list.clear();       // UnsupportedOperationException

Arrays.asList 返回的 List 不能增删元素,只能 set。

1.2 Collections.singletonListCollections.emptyList

List<String> list = Collections.singletonList("a");
list.add("b");      // UnsupportedOperationException
list.remove("a");   // UnsupportedOperationException
list.clear();       // UnsupportedOperationException

这些方法返回的 List 是不可变的。

1.3 List.of (Java 9+)

List<String> list = List.of("a", "b");
list.add("c");      // UnsupportedOperationException
list.remove("a");   // UnsupportedOperationException

List.of 返回的也是不可变集合。

1.4 Map.ofSet.of

同理,Map.ofSet.of 也是不可变的。


2. 只读视图(Unmodifiable Views)

比如 Collections.unmodifiableListCollections.unmodifiableMap

List<String> source = new ArrayList<>();
List<String> list = Collections.unmodifiableList(source);
list.add("a");      // UnsupportedOperationException
list.remove("a");   // UnsupportedOperationException
list.clear();       // UnsupportedOperationException

这些方法返回的是原集合的只读视图,任何修改都会抛异常。


3. 部分集合操作被禁止

有些集合只实现了部分操作,比如:

  • java.util.AbstractList 的默认实现,某些方法没有被子类覆盖时会抛出该异常。
  • java.util.AbstractMapAbstractSet 也是类似。

4. 固定大小集合

如 Arrays.asList 返回的 List,底层是数组,不能改变大小。


5. 自定义集合类未实现某些方法

如果你自己继承了某个集合类,某些方法没有实现,直接调用父类的默认实现,也会抛出该异常。


6. JDK 某些特殊集合

  • Collections.nCopies 返回的 List(固定元素数量,不可变)
  • Collections.emptyListemptySetemptyMap
  • Collections.singletonsingletonMap

7. 迭代器的 remove 操作

有些集合的 iterator 不支持 remove 操作:

List<String> list = List.of("a", "b");
Iterator<String> it = list.iterator();
it.next();
it.remove(); // UnsupportedOperationException

8. 多线程并发集合的某些操作

如 CopyOnWriteArrayList 的 iterator 不支持 remove。


总结

只要你对不可变集合、只读视图、固定大小集合或者未完全实现的集合类调用了修改方法(add、remove、clear、set、put、remove等),就会抛出 UnsupportedOperationException


如何避免?

  • 如果需要修改集合,请用如 new ArrayList<>(...)new HashSet<>(...) 等可变集合。
  • 如果只读,则不要调用修改方法。
  • 检查集合的创建方式,尽量避免对不可变集合进行修改操作。

9. Stream 相关操作

例如,使用 Java 8 Stream API 生成的集合有时也是不可变的:

List<String> list = Stream.of("a", "b").collect(Collectors.toList());
// 默认情况下 Collectors.toList() 返回的是 ArrayList,可变。
// 但如果用 Collectors.toUnmodifiableList() (Java 10+)
List<String> unmodList = Stream.of("a", "b").collect(Collectors.toUnmodifiableList());
unmodList.add("c"); // UnsupportedOperationException

10. 第三方库的不可变集合

很多第三方库(如 Guava、Apache Commons Collections)都提供了不可变集合,比如 Guava 的 ImmutableList

List<String> guavaList = ImmutableList.of("a", "b");
guavaList.add("c"); // UnsupportedOperationException
guavaList.remove("a"); // UnsupportedOperationException

11. Arrays 工具类中的其它方法

除了 Arrays.asList,还有如 Arrays.setAll 返回的集合,也可能是不可变的。


12. 多层包装导致

有时候集合被多层包装,导致你误以为是可变的。例如:

List<String> list = Collections.unmodifiableList(Arrays.asList("a", "b"));
// 虽然底层是 Arrays.asList,但外层包装成了只读视图
list.set(0, "c"); // 仍然 UnsupportedOperationException

13. 子类未覆盖父类方法

比如你继承 AbstractList,只实现了 get 和 size,没实现 remove,那么调用 remove 会抛异常:

class MyList extends AbstractList<String> {
    public String get(int index) { ... }
    public int size() { ... }
    // 没有实现 remove(int index)
}
MyList list = new MyList();
list.remove(0); // UnsupportedOperationException

14. JDK 内部特殊集合

有些 JDK API 返回的集合本身就是只读的,比如:

  • Collections.list(enumeration) 返回的 List
  • System.getProperties().entrySet() 返回的 Set
  • Map.keySet()Map.values()Map.entrySet() 的某些实现

这些集合的某些操作可能不被支持。


15. Map、Set 的只读视图

类似于 List,Map 和 Set 也有只读视图:

Map<String, String> map = Collections.unmodifiableMap(new HashMap<>());
map.put("a", "b"); // UnsupportedOperationException

16. 其他常见误区

  • 有些集合支持部分操作,比如 remove 支持,但 add 不支持,或者反之。
  • 迭代器的 remove() 方法不是所有集合都实现,有些会抛异常。

总结补充

UnsupportedOperationException 本质上是集合设计者用来保护集合不被非法修改的机制。

  • 只读集合:不能修改
  • 固定大小集合:不能增删,只能 set
  • 未完全实现的集合:部分方法不能用
  • 迭代器:不是所有都支持 remove

如何排查

  1. 定位集合的来源:看是怎么创建的,用了哪些工厂方法或包装器。
  2. 查阅文档:官方文档和第三方库文档都会说明哪些操作被支持。
  3. 调试类型:通过 getClass() 打印集合的实际类型,判断底层实现。
  4. 避免误用:如果需要修改集合,始终用标准的可变集合,如 ArrayListHashSetHashMap
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猩火燎猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值