HashSet 抛出 UnsupportedOperationException

Posted

技术标签:

【中文标题】HashSet 抛出 UnsupportedOperationException【英文标题】:HashSet throws UnsupportedOperationException 【发布时间】:2022-01-22 23:14:46 【问题描述】:

我有下面的代码,当我使用remove removeIf 从集合中删除一个项目时,得到一个错误java.lang.UnsupportedOperationException: null

private Set<Speciality> specialities = new HashSet<>();

private void updateSpeciality(SpecialityETAUpdatedEvent evt) 
    if (CollectionUtils.isNotEmpty(this.specialities)) 
        Optional<Speciality> specialityOptional = this.specialities.stream().filter((Speciality speciality) -> speciality.getCode().equals(evt.code)).findFirst();
        if (specialityOptional.isPresent()) 
            this.specialities.remove(specialityOptional.get());// **** Exception thrown here
        
    
    this.specialities.add(new Speciality().code(evt.code).label(evt.label).startDate(evt.startDate));

java.lang.UnsupportedOperationException: null at java.util.Collections$UnmodifiableCollection.remove(Collections.java:1060) 在 com.xxxx.updateSpeciality(EstablishmentAggregate.java:916) 在 com.xxxx.EstablishmentAggregate.on(EstablishmentAggregate.java:909) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 在 java.lang.reflect.Method.invoke(Method.java:498)

【问题讨论】:

请参阅minimal reproducible example。您需要使您的代码示例成为我们可以复制/粘贴、运行和观察与您相同的结果;否则我们无法找出导致问题的原因。 您需要提供堆栈跟踪。 解释在你的调用栈中:你的集合是UnmodifiableCollection;不是HashSet。你给specialities分配了什么? 我想知道堆栈跟踪中的“UnmodifiableCollection”...这可能与在发布的代码中创建的 Set 不同 - 包含 minimal reproducible example 的一个原因(例如, Set.of(...)返回这样一个不可修改的集合) 【参考方案1】:

您确定专业是HashSet 吗?可以在某处创建为不同的类型吗?例如,UnsupportedOperationException 可以扔到不可修改的集合上。

您似乎可以在某处设置specialities,并使用显式setSpecialities 传递一个Set,但不是HashSet

在这种情况下,实例化 Set 的类不支持 removeremoveIf 方法,它们的实现类似于以下代码:

public boolean remove(Object o) 
   throw new UnsupportedOperationException();

一种创建不可修改Set的方法是例如使用java 9 Set.of的函数:

返回一个不可变集合包含零个元素

正如 javadoc 中所解释的:

Set.of() 静态工厂方法提供了一种创建不可变集合的便捷方式。这些方法创建的 Set 实例具有以下特点:

它们在结构上是不可变的。不能添加或删除元素。 调用任何 mutator 方法总是会导致抛出 UnsupportedOperationException。但是,如果包含的元素本身是可变的,这可能会导致 Set 行为不一致或其内容似乎发生变化。

【讨论】:

实际的documentation 更加严格:“它们不可修改。”不仅“结构上不可变”(因为没有索引访问或任何其他更改元素的方法,这并不重要:-))【参考方案2】:

以下是我将如何在集合中更新或添加条目。

import java.util.*;
class Record 
    int id, val;
    Record(int id)  this.id = id; 
    Record(int id, int val)  this.id = id; this.val=val;
  
    public boolean equals(Object o)
        return o instanceof Record ? id==((Record)o).id : false;
    
    public int hashCode()   
        return Objects.hashCode(id);
    
    public String toString()
        return String.format("Container[id=%d, val=%d]", id, val);
    


class RecordSet extends HashSet<Record> 
    Record addOrUpdate(Record c)
        remove(c);
        add(c);
        return c;
    


public class Main 
    public static void main(String[] args) 
        RecordSet set = new RecordSet();
        set.add(new Record(1,100));
        set.add(new Record(2,200));
        set.add(new Record(3,300));
        
        System.out.println("Before: " + set);
        
        Record c1 = new Record(1,500);  //update existing record
        Record c2 = new Record(4,400);  //new record
        
        set.addOrUpdate(c1);
        set.addOrUpdate(c2);
        
        System.out.println("After: " + set);
    

【讨论】:

以上是关于HashSet 抛出 UnsupportedOperationException的主要内容,如果未能解决你的问题,请参考以下文章

怎样在C#中把0-10这11个数随机顺序不重复的放到集合里面?

java的List 的remove抛出异常

Set类

HashSet源码解析

HashSet源码解析

Set(一):HashSet、LinkedHasSet源码浅析