User Tools

Site Tools


java:immutable-objects

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
java:immutable-objects [2023/04/08 01:00] – created odeftajava:immutable-objects [2023/07/04 19:36] (current) – external edit 127.0.0.1
Line 7: Line 7:
   * **Thread safety**: they cannot change its state, so they cannot be corrupted by thread interference or observed in an inconsistent state.   * **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.   * **Atomicity of failure**: if an immutable object throws an exception, it's never left in an undesirable or indeterminate state.
-  * **Protection against null reference errors**.+  * **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 ===== ===== Disadvantages =====
  
 Immutable classes require a separate object for each distinct value. Creating these objects can be costly, especially if they are large. 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 =====
 +<code java>
 +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);
 +
 +    }
 +}
 +</code>
 +Output:
 +<code>
 +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)
 +</code>
 +
 +===== 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
 +
 +<note tip>
 +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.</note>
  
java/immutable-objects.1680904854.txt.gz · Last modified: 2023/07/04 19:36 (external edit)