User Tools

Site Tools


java:immutable-objects

Immutable objects

An immutable object cannot be modified after it was created. Instead, a copy of the object is returned.

Advantages

  • Thread safety: they cannot change its state, so they cannot be corrupted by thread interference or observed in an inconsistent state.
  • Atomicity of failure: if an immutable object throws an exception, it's never left in an undesirable or indeterminate state.
  • Predictability: objects won't change due to coding mistakes or by 3rd party libraries. As long as we reference a data structure, we know it is the same as at the time of its creation.
  • Validity: is not needed to be tested again and again. Once we create the immutable object and test its validity once, we know that it will be valid indefinitely.

Disadvantages

Immutable classes require a separate object for each distinct value. Creating these objects can be costly, especially if they are large.

How to implement an immutable object

  • make fields private and final
  • methods that alters the object state should return new objects
  • make copies of caller provided data (except primitives or immutable objects)
  • ensure the class cannot be overridden (make the class final, or use static factories and keep constructors private)
  • don't provide setter methods for variables.

Example of immutable class

import java.util.ArrayList;
import java.util.List;
 
final class Record {
 
    private final long id;
    private final String name;
    private final List<String> tokens;
 
    public Record(long id, String name, List<String> tokens) {
        this.id = id;
        this.name = name;
 
        /*  This works, but:
         - it will always duplicate elements
         - the same copy should be used also in getTokens() method.
        */
        //this.tokens = new ArrayList<>(tokens);
 
        /*  If tokens is already unmodifiable (for ex. was formed using List.of),
            then it will not duplicate elements.
            Also, it will prevent the tokens to be modified
            (it will throw java.lang.UnsupportedOperationException).
         */
        this.tokens = List.copyOf(tokens);
    }
 
    public long getId() {
        return id;
    }
 
    public String getName() {
        return name;
    }
 
    /**
     * No simple setters, return another copy of the object.
     * @param name
     * @return Record
     */
    public Record withName(String name) {
        return new Record(id, name, tokens);
    }
 
    public List<String> getTokens() {
        //return new ArrayList<>(tokens);
        return tokens;
    }
 
    @Override
    public String toString() {
        return "Record (id = " + id + ", name='" + name + '\'' + ", tokens=" + tokens + ")";
    }
}
 
class TestRecord {
 
    public static void main(String[] args) {
        List<String> tokens = new ArrayList<>();
        tokens.add("Token 1");
        tokens.add("Token 2");
 
        Record record = new Record(1, "One", tokens);
        System.out.println(record);
 
        tokens.remove(0);
        System.out.println(record);
 
        System.out.println(record.withName("Two"));
 
        record.getTokens().add("Token 3");
        System.out.println(record);
 
    }
}

Output:

Record (id = 1, name='One', tokens=[Token 1, Token 2])
Record (id = 1, name='One', tokens=[Token 1, Token 2])
Record (id = 1, name='Two', tokens=[Token 1, Token 2])
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:71)
	at java.base/java.util.ImmutableCollections$AbstractImmutableCollection.add(ImmutableCollections.java:75)
	at ro.medjava.immutability.TestRecord.main(Record.java:65)

Immutable classes in JDK

Some immutable classes from java api:

  • java.lang.String
  • java.lang.Integer
  • java.io.File
  • java.util.Locale
  • java.awt.Font
  • java.net.InetSocketAddress
Immutable classes can also be created using builder pattern. Builder Pattern is a better option if the immutable class has a lot of attributes and some of them are optional.
java/immutable-objects.txt · Last modified: 2023/07/04 19:36 by 127.0.0.1