Are we using mutable objects too much?

By default any object you create in java is mutable.

And so we end up using mutable objects more often.

But Java team themselves suggest to use Immutable objects more.

From https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html :

Maximum reliance on immutable objects is widely accepted as a sound strategy for creating simple, reliable code

One reason why developers wouldn’t want to use immutable objects is because of the cost of creating new objects is high , say if you want to update an existing object and if it is immutable then you need to create a new object and copy it.

But Java says that the cost is ignorable compared to the advantages of using immutable objects:

Programmers are often reluctant to employ immutable objects, because they worry about the cost of creating a new object as opposed to updating an object in place. The impact of object creation is often overestimated, and can be offset by some of the efficiencies associated with immutable objects. These include decreased overhead due to garbage collection, and the elimination of code needed to protect mutable objects from corruption.

Also Joshu Bloch , author of Effective Java suggests to prefer immutable objects over mutable objects in his book:

Classes should be immutable unless there’s a very good reason to make them mutable…If a class cannot be made immutable, limit its mutability as much as possible.

Here are few reasons why creating an immutable object is preferable to a mutable one:

1. Immutable objects prevent hidden side effects:

Consider the below code:

package immutable;

public class ImmutableDemo {

	
	
	public static void main(String a[]) {
		
		
		
		HiddenSideEffectDemo hiddenSideEffect  =new HiddenSideEffectDemo();
		
		
		Request request = new Request();
		
		request.setMessage("I prefer mutable objects");
		
		
		System.out.println("Message is "+request.getMessage());
		
		hiddenSideEffect.execute(request);
		
		
		System.out.println("Message is "+request.getMessage());
	}
}

I am creating a “Request” object and setting a value for its message attribute

And then I am passing that request for further processing to another method in another class.

When I run the above I get the below ouput:

Message is I prefer mutable objects
Message is Do you still believe in mutable objects?

Oops the message got changed.

Assume I didn’t expect the calling method to change my request , I just wanted it to read the request object and do something with the value read.

But it has changed.

Because the developer who wrote the calling method did this :

package immutable;

public class HiddenSideEffectDemo {

	public void execute(Request request) {

		// read the request and do some logic

		boolean mutableMessage = request.getMessage().contains("mutable");
         // do something here


		// set the message for handling some other requirement to the //original developer's dismay

		request.setMessage("Do you still believe in mutable objects?");


       // do something here
	}

}

Here is the Request class:

package immutable;

public class Request {

	
	
	private String message;
	
	
	public String getMessage() {
		
		
		return message;
	}
	
	public void setMessage(String message) {
		
		this.message  = message;
	}
}

The above example is simplistic. In real world scenario the methods could span several lines of code and the change could be difficult to spot.

Now to fix this you need to make the Request object as immutable

Here is the immutable version of Request object:

package immutable;

public final class ImmutableRequest {

	
	private final String message;
	
	
	public ImmutableRequest(String message) {
		
		this.message = message;
	}
	
	public String getMessage() {
		
		return message;
	}
	
}

Below are the changes made:

  1. The class is marked as final so that it cannot be inherited and subclasses cannot modify the class’s behavior
  1. The fields are marked as final and private so that they cant be changed or accessed outside the class
  2. There is no setter method so that the value of “message” cannot be changed. It can be set only using the constructor during the creation of the request object.

Now let’s try to run the above code using the new immutable request object:

package immutable;

public class ImmutableDemo {

	public static void main(String a[]) {

		HiddenSideEffectDemo hiddenSideEffectImmutable = new HiddenSideEffectDemo();

		ImmutableRequest immutableRequest = new ImmutableRequest("I prefer immutable objects");

		System.out.println("Message is " + immutableRequest.getMessage());

		hiddenSideEffectImmutable.execute(immutableRequest);

		System.out.println("Message is " + immutableRequest.getMessage());
	}
}

Here is the HiddenSideEffectDemo class , it complains that request object doesn’t have the setter method:

The only way we can change this value is using the constructor ( new ImmutableRequest(“new message”) ).

But that will create a new object and the original object will remain unchanged.

Let’s try to create a new request object and assign it to the original object:

package immutable;

public class HiddenSideEffectDemo {

	public void execute(ImmutableRequest request) {

		// read the request and do some logic

		boolean mutableMessage = request.getMessage().contains("mutable");
		// do something here

		// set the message for handling some other requirement to the original
		// developer's dismay

		request = new ImmutableRequest("Do you still prefer a immutable object?");

		// do something here
	}

}

The compiler didn’t complain! This is because the original object is not changed.

A new object is created and its scope lies within this method.

When you run the application again , you get the below output:

The message is unchanged.

The original object remains unchanged even though we created a new object inside the execute method of “HiddenSideEffectDemo” class (its scope lies only within the method)

Now the developer can relax that his object “Request” will have a fixed state and behavior and the code will be more bug free.

2) Immutable objects provide thread safety

Consider this example provided in Java docs (source):

public class SynchronizedRGB {

    // Values must be between 0 and 255.
    private int red;
    private int green;
    private int blue;
    private String name;

    private void check(int red,
                       int green,
                       int blue) {
        if (red < 0 || red > 255
            || green < 0 || green > 255
            || blue < 0 || blue > 255) {
            throw new IllegalArgumentException();
        }
    }

    public SynchronizedRGB(int red,
                           int green,
                           int blue,
                           String name) {
        check(red, green, blue);
        this.red = red;
        this.green = green;
        this.blue = blue;
        this.name = name;
    }

    public void set(int red,
                    int green,
                    int blue,
                    String name) {
        check(red, green, blue);
        synchronized (this) {
            this.red = red;
            this.green = green;
            this.blue = blue;
            this.name = name;
        }
    }

    public synchronized int getRGB() {
        return ((red << 16) | (green << 8) | blue);
    }

    public synchronized String getName() {
        return name;
    }

    public synchronized void invert() {
        red = 255 - red;
        green = 255 - green;
        blue = 255 - blue;
        name = "Inverse of " + name;
    }
}

The above class is used to create a color object using Red , Green and Blue color combinations. All the methods are marked with synchronized keyword so it looks like all the methods are thread safe.

But as cited in the doc , consider the below code:

SynchronizedRGB color =
    new SynchronizedRGB(0, 0, 0, "Pitch Black");
...
int myColorInt = color.getRGB();      //Statement 1
String myColorName = color.getName(); //Statement 2

A new color object representing “Pitch Black” is created in the above example.

Let’s say one thread is executing statement 1 and gets the representation of Pitch Black color object.

And before statement 2 is executed let’s say another thread sets a new blue color object using set(int red,int green,int blue,String name){} method

Then if the initial thread executes statement 2 it gets the blue color object instead of Pitch black

This can be avoided by putting both the statements in a synchronized block.

A more elegant way would be to create a immutable version of the class SynchronizedRGB.

Since you can’t modify the state of an object once it is created , it will be always consistent in a multi threaded environment.

3) Immutable objects can be used as Map keys:

If you ever want to use objects as map keys and you chose a mutable object for that your program is likely to behave inconsistently as the key object can be modified which means the key mapping will be inaccurate.

Immutable objects can safely be used in this case as they are never going to change

4) Immutable objects can be cached

If you want to improve the latency of accessing objects in your application , you can probably use a cache and store the objects in a cache for quicker access.

Immutable objects are a good candidate for this since their state cannot be changed and will always reflect the latest value.

5) Immutable objects can prevent Null pointer exceptions

Since all fields in a immutable class should be marked as final , they need to be initialized inside the class.

Else the compiler will complain:

So if you access any of the fields of an immutable object in your code, it will be guaranteed to have a value unless you initialize the fields with null value itself in the immutable class.

6) Immutable objects help in parallel processing

Let’s say you are spinning two tasks concurrently in Java.

Both the tasks use the same type of object.

If they are mutable there is a chance that one of the threads alter the values of the object used by the other thread.

If they are immutable you can safely do the parallel processing.

7) Immutable objects ensure atomicity

Let’s say you are dealing with an immutable object inside a method and an exception occured.

You can catch the exception and proceed with the object without the fear of the object being modified

Whereas in case of mutable objects the state of the object could be inconsistent as it could have been modified in the try{} block.

8) Immutable object can help in loosely coupled methods

If you are passing an object between two methods and if it is mutable it is likely that the state of the object can be changed by one method and so the other method then has to deal with the new state of the object.

This provides strong coupling between two methods.

This can be avoided by using immutable objects.

The two methods can work with the object without worrying what the other method could do to it. This is similar to point 1 (preventing hidden side effects)

9) Immutable objects help in functional programming

Functional programming is a programming paradigm where given a method if the same input is passed to it it will always produce the same output.

This can be achieved using immutable objects since they have a fixed state.

10) Immutable objects prevent logically invalid objects

When you create a mutable object , it can be changed later by a developer and can be assigned logically invalid values / any random values by the developer.

This is not possible with immutable objects as once created they can never be changed and hence never be assigned random values for their attributes.

11) Immutable objects preserve object identity

Let’s say you create an object with an unique identifier.

If it is mutable this identifier can be later changed and the object then looses its old identity and gets a new identity.

This can be prevented using immutable objects.

References:

https://www.leadingagile.com/2018/03/immutable-in-java/

https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html

https://www.infoworld.com/article/2073003/is-a-java-immutable-class-always-final-.html?page=2

https://www.linkedin.com/pulse/20140528113353-16837833-6-benefits-of-programming-with-immutable-objects-in-java/


Posted

in

,

by

Comments

2 responses to “Are we using mutable objects too much?”

  1. Sameer Avatar

    Java 17 records are useful in this scenario!

    1. Vijay SRJ Avatar
      Vijay SRJ

      yeah they will work for most use cases . One scenario where it won’t work is if the fields of record fields themselves have mutable fields , records don’t guarantee their immutability . Hence records are called shallowly immutable !

Leave a Reply to Vijay SRJCancel reply

Discover more from The Full Stack Developer

Subscribe now to keep reading and get access to the full archive.

Continue reading