Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enforce immutable collections in a Java record?

Java records are used to implement shallowly immutable data carrier types. If the constructor accepts mutable types then we should implement explicit defensive copying to enforce immutability. e.g.

record Data(Set<String> set) {
    public Data(Set<Thing> set) {
        this.set = Set.copyOf(set);
    }
}

This is mildly annoying - we have to

  1. implement an old-school POJO constructor (replicating the fields) rather than using the canonical constructor and
  2. explicitly initialise every field just to handle the defensive copy of the mutable field(s).

Ideally what we want to express is the following:

record SomeRecord(ImmutableSet<Thing> set) {
}

or

record SomeRecord(Set<Thing> set) {
    public SomeRecord {
        if(set.isMutable()) throw new IllegalArgumentException(...);
    }
}

Here we use a fictitious ImmutableSet type and Set::isMutable method, in either case the record is created using the canonical constructor - nice. Unfortunately it doesn't exist!

As far as I can tell the built-in collection types (introduced in Java 10) are hidden, i.e. there is no way to determine if a collection is immutable or not (short of trying to modify it).

We could use Guava but that seems overkill when 99% of the functionality is already in the core libraries. Alternatively there are Maven plug-ins that can test classes annotated as immutable, but again that's really a band-aid than a solution.

Is there any pure-Java mechanism to enforce a immutable collection?

like image 580
stridecolossus Avatar asked May 19 '21 13:05

stridecolossus


People also ask

How do you make a Java collection immutable?

In Java 8 and earlier versions, we can use collection class utility methods like unmodifiableXXX to create immutable collection objects. If we need to create an immutable list then use the Collections. unmodifiableList() method.

Is Java record immutable?

Records are immutable data classes that require only the type and name of fields. The equals, hashCode, and toString methods, as well as the private, final fields and public constructor, are generated by the Java compiler.

Is collections immutable in Java?

About Immutability. The collections returned by the convenience factory methods added in JDK 9 are conventionally immutable. Any attempt to add, set, or remove elements from these collections causes an UnsupportedOperationException to be thrown.

How to create immutable collections in Java 9?

From Java 9, static factory methods are introduced to create immutable collections. 1) Immutable List : List.of () 2) Immutable Set : Set.of () 3) Immutable Map : Map.of () or Map.ofEntries ()

What are the different types of immutables in Java 9?

1) Immutable List : List.of () 2) Immutable Set : Set.of () 3) Immutable Map : Map.of () or Map.ofEntries () Java 9 Immutable collections and unmodifiable collections returned by the Collections.unmodifiableXXX () wrapper methods are not the same.

What is immutablelist in Java and how to change it?

Immutable collections can't be changed at all - they don't wrap another collection - they have their own elements. Unlike Collections.unmodifiableList (java.util.List<? extends T>), which is a view of a separate collection that can still change, an instance of ImmutableList contains its own private data and will never change.

What is the difference between immutable and unmodifiable collections?

Unmodifiable collections are just the read-only views of the original collection. You can perform modifying operations on the original collection and those modifications will be reflected in the collections returned by these methods. But, immutable collections returned by Java 9 static factory methods are 100% immutable.


1 Answers

You can do it already, the arguments of the constructor are mutable:

record SomeRecord(Set<Thing> set) {
    public SomeRecord {
        set = Set.copyOf(set);
    }
}

A related discussion mentions the argument are not final in order to allow such defensive copying. It is still the responsibility of the developer to ensure the rule on equals() is held when doing such copying.

like image 111
M A Avatar answered Oct 18 '22 03:10

M A