Are String, Date, Method immutable?

Overview

There are many forms of immutability and each can have different uses. It is worth knowing the difference between them. Immutable classes are simpler to reason about and are very useful in multi-threaded contexts as they do not suffer from thread-safety issues.

Technically Immutable

An object is technically immutable if its state doesn't change after construction.

This includes the primitive wrapper classes, but excludes many classes described as immutable.

From Integer
public class Integer {
    private final int value;
}
As you can see nothing should change after the object is created.

Note: even this immutable object can be changed using reflection, however that is usually ignored for the purposes of discussing immutability.

If you consider reflection, only inlined compile time constants are effectively immutable as a copy is placed in every usage.

Logically Immutable

A class is logically immutable provided the exposed interface never changes. The internal state can change to cache calculated values but this should not change the result of any combination of methods (though the timing of those methods could change)

From String
public final class String {
    /** Cache the hash code for the string */
    private int hash; // Default to 0

    public int hashCode() {
 int h = hash;
        int len = count;
 if (h == 0 && len > 0) {
     int off = offset;
     char val[] = value;

            for (int i = 0; i < len; i++) {
                h = 31*h + val[off++];
            }
            hash = h;
        }
        return h;
    }
}
The field hash can change and you would be able to see it change in the debugger or using reflection. However, the class is logically immutable as the only change is to cache a derived result and there is no way the caller can tell the difference using normal methods calls.

Immutable by Convention

Many class are treated as immutable by convention. The immutability is not enforced by the language, however it is understood that the state of the object is not changed either using a written policy all developers adhere to, or the mutable functionality is understood to be never used. From java.util.Date
public void setTime(long time) {
 fastTime = time;
 cdate = null;
    }
When using Date on some projects, there may be a convention to never use setTime() and rather create a new Date(long) every time a Date changes. This Immutable by Convention can be enforced using code analysis, or at runtime with an assert or explicit runtime check.

Limited Immutability

This occurs when a instance of a class has a distinct life cycle. An instance can be mutable during a specific phase and later Immutable by Convention (because there will be no more changes by design) From AccessibleObject parent of Method, Field, Constructor
// Indicates whether language-level access checks are overridden
    // by this object. Initializes to "false". This field is used by
    // Field, Method, and Constructor.
    boolean override;
The method setAccessible can change this override which changes the value returned by isAccessible(). As such the class is mutable. A typical use case is to not use setAccessible or to call it only once. From this time on that instance can be shared safely as it were immutable. Another form of limited immutability is in recycling mutable objects. There may be a stage when new market data or an object builder is set in recycled objects. In another clearly defined stage of the application, the market data or object builder is assumed not to change. This approach can give the advantages of a mutable object (through recycling and reducing copies) and the thread safety of immutable objects. It requires the application designed to clearly determine when an object can/cannot change.

Conclusion

While not technically immutable, I would describe String as Logically Immutable, Date can be Immutable by Convention and Method can have Limited Immutability.

Comments

Popular posts from this blog

Java is Very Fast, If You Don’t Create Many Objects

Low Latency Microservices, A Retrospective

Unusual Java: StackTrace Extends Throwable