Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Implementing Values With Immutable Classes

DZone's Guide to

Implementing Values With Immutable Classes

Dive into thread safety, value objects, primitive types, and immutable classes as we explore some recommended practices.

· Java Zone ·
Free Resource

Download Microservices for Java Developers: A hands-on introduction to frameworks and containers. Brought to you in partnership with Red Hat.

Classes representing values should have the same properties as primitive types. Primitive types represent basic values like int or char in Java. Primitive types have no identity and are immutable.

In the following, we will see that those two properties are also useful for classes representing properties.

No Identity

Two values are equal if they have the same external visible state: For example, if you have two variables (a and b) with the value 5, they are equal:

int a = 5;
int b = 5;
a == b // true


Immutable

Values are immutable. If you a modify a value, it becomes a new value. In the following example, we modify the variable a, which leads to a new value b. a and b are not equal.

int a = 5
int b  = a + 2;
a == b // false

A Value Class

Now let us look at a class representing a value with those two properties, the java.time.Instant class. This class represents an instant in time. Let us first look at the field declaration of this class:

package java.time;

public final class Instant
{
    private final long seconds;
    private final int nanos;    
    // static fields and methods omitted 
}


Declaring the field final makes this class immutable. Declaring a field as final (as the two fields in the example, lines 5 and 6) lets the compiler check that the fields are not modified after the constructor of the class was called. Note that final is a field modifier. It makes the field itself immutable, not the object the field references. So the type of the final field must also be immutable or a primitive type like in the example.

Next, let us look at the equal method to see how equality is implemented for this class:

public boolean equals(Object otherInstant) {
        if (this == otherInstant) {
            return true;
        }
        if (otherInstant instanceof Instant) {
            Instant other = (Instant) otherInstant;
            return this.seconds == other.seconds &&
                   this.nanos == other.nanos;
        }
        return false;
    }


As we see, two Instant objects are equal if their external visible state is equal.

Immutability Using an Identity

Now let us look at a class that is immutable but uses its identity for equality — the Object class. The Object class is useful when you only need an identity but no state, like in the following example, from the JDK 9 java.util.concurrent.CopyOnWriteArrayList, where we need the identity as a monitor for synchronization:

public class CopyOnWriteArrayList<E>
{
  final transient Object lock = new Object()
   public boolean add(E e) {
        synchronized (lock) {
            // other statements omitted
        }
    }
}


To represent a value of a class with identity is not useful.

No Identity but Mutable

The following shows a mutable value class, the java.util.Date class:

public class Date
{
     private transient BaseCalendar.Date cdate;
     private transient long fastTime;
     public void setTime(long time) {
        fastTime = time;
        cdate = null;
    }
    public boolean equals(Object obj) {
        return obj instanceof Date && getTime() == ((Date) obj).getTime();
    } 
    public long getTime() {
        return getTimeImpl();
    }
    private final long getTimeImpl() {
        if (cdate != null && !cdate.isNormalized()) {
            normalize();
        }
        return fastTime;
    } 
    // static fields and other methods omitted 
}


The two fields (cdate and fastTime) are not final and can be changed by the setTime method, making the class mutable. The equals method checks the externally visible state for equality. While it is possible to implement values with mutable classes, immutable classes are easier to use.

Advantages of Immutable Value Classes

Immutable classes cannot change their state. This property is useful in specific scenarios in single-threaded programs, for example when you use them as keys in hash maps. And it makes writing multi-threaded programs much easier.

Immutable classes do not change their value in the middle of an operation without using synchronized blocks. By avoiding synchronization blocks, you avoid deadlocks. And since you are always working with an unchangeable, consistent state you avoid race conditions.

Usage of Identity

While it is still possible to access the identity of a value object, it is probably an error. For example, the use of == instead of equals is probably incorrect:

Integer a = new Integer(5);
Integer b = new Integer(5);
a.equals(b) // true
a == b 


You probably expect true when you compare two Integers of value 5, so the use of == is incorrect. The following methods are using the identity of the object and should be avoided when using value classes:

  • synchronized statement
  • System.identityHashCode
  • Object.notify and wait

The Future: JEP 169, Value Objects

Implementing values using classes requires more memory than their primitive counterparts. A solution to this problem is implemented by Java Enhancement Proposal 169, Value Objects. It will allow you to create value classes with similar memory characteristics as primitive types.
The idea is to implement a new operator (lockPermanently), which converts an object into a new state with memory consumption similar to a primitive type. Using an operation that requires the identity of the value object like == or synchronized on such a locked object will be forbidden.

Conclusion and What Is Next

Primitive types represent basic values. Primitive types are immutable and have no identity. We have seen how to implement classes with the same properties. The usage of the identity of a value class, while still possible, is probably an error. Making value classes immutable makes them easier to use, especially for thread safe software.

In the next blog post, we will look at one type of value classes, messages, to write thread safe software. In the meantime, if you want to test whether your application is thread-safe, try vmlens for free. I would be glad to hear from you if you use value classes in your application.

Download Building Reactive Microservices in Java: Asynchronous and Event-Based Application Design. Brought to you in partnership with Red Hat

Topics:
java ,immutability ,concurrent ,value objects ,thread safety ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}