An immutable object cannot be modified after it was created. Instead, a copy of the object is returned.
Immutable classes require a separate object for each distinct value. Creating these objects can be costly, especially if they are large.
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)
Some immutable classes from java api: