Advanced Immutable Objects in Java

What are Immutable Objects in Java?

They are multifunctional immutable objects that can be used in different parts of the program.

For example, they can be immutable objects in a multithreaded environment to work with data. They can also be complex constants that help you avoid unnecessary memory usage and garbage collector overloading. Separately we should mention immutability when working with collections.

The Main Parameters of Immutable Classes

To say that a class is immutable it must meet the following criteria:

  • Do not provide methods that modify the object’s state. These methods can directly modify the object state of the class.
  • Make sure that the class cannot be inherited. By inheriting a class, you can easily access its fields, where you can then easily modify them.
  • Make all fields in the class final. So we show our intention about whether the fields in the class can be modified.
  • Make all fields in the class private. By adding this attribute to the field, we will close off the access where you can modify the fields of the class directly.
  • Make sure that the class does not give exclusive access to modifiable objects. If for example there are complex objects in a class (collections, other complex classes, etc) you should consider making a copy of the field, so it’s not possible to modify it by reference.

Practical Use of Immutable Objects

In practice, immutability allows to build of more stable programs and its principles can often be applied to the fundamental parts of the software.

For example, these can be complex constants and strings that can be used either as program configuration or as underlying data.

Complex –°onstants

There can be many static constants in a project to represent different states and statuses. If you take, for example, the way the basic wrapper classes of simple types work under the hood, you can see that almost all of them are immutable.

For example, the Boolean class and how object states are set there:

public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);

public static Boolean valueOf(boolean b) {
        return b ? TRUE : FALSE;
}

Also an example with a BigInteger:

public static final BigInteger ZERO;
public static final BigInteger ONE;
public static final BigInteger TWO;
public static final BigInteger TEN;


private static final BigDecimal ZERO_THROUGH_TEN[] = {
    new BigDecimal(BigInteger.ZERO,       0,  0, 1),
    new BigDecimal(BigInteger.ONE,        1,  0, 1),
    new BigDecimal(BigInteger.TWO,        2,  0, 1),
    new BigDecimal(BigInteger.TEN,        10, 0, 2),
};

...

totalBig = totalBig.divide(BigInteger.TEN);

Java Concurrency In Multithreading – Java Tread Safety

Sometimes when an object is processed in a multithreaded environment you need to separate variables that need to be unique within a separate thread. There can be many reasons for this.

A ThreadLocal class can be used for this purpose. Below is an example of using local variables for each individual thread.

public class ThreadExample {
    
    public static final ThreadLocal<StateExampleHolder> statePerThreadExample = new ThreadLocal<StateExampleHolder>() {
        
        @Override
        protected StateExampleHolder initialValue() {
            return new StateExampleHolder("started");  
        }
    };

    public static StateExampleHolder getStatus() {
        return statePerThreadExample.get();
    }
}

In Collections

As you know, often some collections consist of a key-value pair. If you take a closer look at, for example, a HashMap collection, you can see that, thanks to the key hash, the collection’s internal mechanism determine in which tank to put the object.

Imagine that the key will be modifiable. Suppose you put an object in a collection with a particular key, such as “one”. Then in the process, the key object changed the hash code and internal state. Literally, the value became “two”.

From the example above, it is obvious that we have already lost the value of the key “one” and it will be impossible to retrieve it from the collection.

In this case, immutability solves the problem of losing objects in the collection, because the state and hash code cannot be changed, nothing is lost.

String Immutable

The string is probably one of the most frequently used classes. We have previously written about String Pool, and how strings are stored in memory, and we also did a basic overview of the String class in Java.

As you know, strings themselves are immutable. Each time a string is modified, a new object of the String class is created. So for immutable strings, we have StringBuilder and StringBuffer.

What about the string literals? If for example the reference to the string changes, does the value also change? Let’s look at an example:

String str1 = "Java is the best program language in the world";

String str2 = str1;
System.out.println(str2);

str1 = "No –°++ the first";
System.out.println(str2);

Since the strings are really immutable, the result will be obvious:

Java is the best program language in the world

Java is the best program language in the world

List of Commonly Used Immutable Classes in Java

Almost all classes wrap primitive types: Integer, String, Short, Boolean, BigInteger, BigDecimal, and others.

More on the Topic, for Those Who Are Too Lazy to Read:

Related posts

Leave a Comment