Home > Software design >  HashSet throws UnsupportedOperationException
HashSet throws UnsupportedOperationException

Time:12-22

I have the below code, when i remove an item from a Set using remove or removeIf, a get an error 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) at com.xxxx.updateSpeciality(EstablishmentAggregate.java:916) at com.xxxx.EstablishmentAggregate.on(EstablishmentAggregate.java:909) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498)

CodePudding user response:

Are you sure that specialities is an HashSet? Can be created somewhere as a different type? The UnsupportedOperationException can be thrown on an unmodifiable set for example.

It seems that somewhere you can set the specialities with an explicit setSpecialities passing an object that is a Set, but not an HashSet.

In this case there are classes instantiating Set that doesn't support the remove and removeIf methods and their implementation is something like the following code:

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

A way to create an unmodifiable Set is for example using the function of java 9 Set.of:

Returns an immutable set containing zero elements

And as explained in the javadoc:

The Set.of() static factory methods provide a convenient way to create immutable sets. The Set instances created by these methods have the following characteristics:

  • They are structurally immutable. Elements cannot be added or removed. Calling any mutator method will always cause UnsupportedOperationException to be thrown. However, if the contained elements are themselves mutable, this may cause the Set to behave inconsistently or its contents to appear to change.

CodePudding user response:

Here's how I would update or add an entry in the set.

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);
    }
}
  • Related