Geek Culture
Published in

Geek Culture

Immutability and its Importance

What is immutability?

The dictionary meaning of this word is literally — not changing over time. In programming language also the word is used for its similar meaning. There are some programming languages where the immutability of the objects is implicit, but for java, it is not the case. Let’s see it in detail with an example.

Here in this example, we will create an object of class ‘User’. A user consists of the attributes like name, id, date of birth, and address. Seems like a simple class to create. And if we are not familiar with immutability then most probably, we will end up creating the following class.

public class User {private String name;private Long id;
private Date dateOfBirth;
private StringBuilder address;
public User(String name, Long id, Date dateOfBirth, StringBuilder address) {
this.name = name;
this.id = id;
this.dateOfBirth = dateOfBirth;
this.address = address;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public Date getDateOfBirth() { return dateOfBirth; }
public void setDateOfBirth(Date dateOfBirth) { this.dateOfBirth = dateOfBirth; }
public StringBuilder getAddress() { return address; }
public void setAddress(StringBuilder address) { this.address = address; }
}

This is perfectly fine if you don't want objects of User to be immutable. But if you want an immutable object then you need to modify your code. Before modification, let's test the above code.

@Test
void testImmutability() {
User user = new User("TestName", 1234L, new Date(1990, 1, 1), new StringBuilder("India"));user.setName("AnotherName");
user.setId(3456L);
user.setDateOfBirth(new Date(2020, 1, 1));
user.setAddress(new StringBuilder("CountryDoesNotExist"));
}

By the definition of immutability, the object ‘user’ should not change its state, which means all the attributes of the user should not be editable or no other method should update its value or reference. So simple! Remove the setter methods, will it work? let’s see…

User class version — 2

private Long id;
private Date dateOfBirth;
private StringBuilder address;
public User(String name, Long id, Date dateOfBirth, StringBuilder address) {
this.name = name;
this.id = id;
this.dateOfBirth = dateOfBirth;
this.address = address;
}
public String getName() { return name; }
public Long getId() { return id; }
public Date getDateOfBirth() { return dateOfBirth; }
public StringBuilder getAddress() { return address; }

}

Let's test again -

@Test
void testImmutability() {
User user = new User("TestName", 1234L, new Date(1990, 1, 1), new StringBuilder("India"));assertEquals("TestName", user.getName());
assertEquals(1234L, user.getId());
assertEquals(new Date(1990, 1 ,1), user.getDateOfBirth());
assertEquals("India", user.getAddress().toString());
}

No setter methods, no other methods to update the values, and if you run the above test it will be successful! Seems like we achieve it!

But there is one more issue in the above code, let's see this in the following modified test.

@Testvoid testImmutability() {User user = new User("TestName", 1234L, new Date(1990, 1, 1), new StringBuilder("India"));user.getAddress().append(" Some addition Address");
user.getDateOfBirth().setMonth(6);
assertEquals("TestName", user.getName());
assertEquals(1234L, user.getId());
assertEquals(new Date(1990, 1 ,1), user.getDateOfBirth());
assertEquals("India", user.getAddress().toString());
}

If you observe, address and date of birth are changed even without setter methods, because both ‘StringBuilder’ and ‘Date’ objects are mutable in nature. But ‘Name’ (String) and ‘Id’ (Integer) are not. Therefore, we need to make some provisions for the attributes which are mutable in nature. Let's see in the example.

public Date getDateOfBirth() {
return new Date(this.dateOfBirth.getYear(), this.dateOfBirth.getMonth(), this.dateOfBirth.getDate());
}
public StringBuilder getAddress() {
return new StringBuilder(this.address);
}

I have just updated the getter methods in the above code snippet, where we are copying the object and then returning the copy from the getter method. If you update these getter methods in your class and run the test, this time your test will run successfully.

There is one more rule to make a class immutable, we need to make that class final. But in my opinion, this is not the most important rule, because we don't create subclasses for such kinds of classes.

Application of Immutable classes

The major use case is where you are calculating the hash of your object. Hash is nothing but the mathematical function which returns an integer value. Hash is generally calculated to assign a unique value to an object, therefore while calculating the hash, it is a good practice to consider all the attributes while calculating it.

Let’s consider the User class which we have previously taken as an example. We have four attributes in it and we will create a hash from all those four attributes. Creating a hash simply means overring the hashcode method from the Object class and writing a meaningful hash function!

@Override
public int hashCode() {
return Objects.hash(address, dateOfBirth, id, name);}

Now consider that you have created five objects of your User class and your class is not updated to create immutable objects. You put all your objects in a Set or a Map(as a key). Now somewhere in your code, you updated the state of the user object which you just put in the Set/Map. The Set/Map works on the principle of hashing, so it stores the objects as per the hashcode generated while putting them in the Set/Map. Therefore while putting the objects in the Set/Map user object was having a different hashcode and after changing the state of the object it might have different hashcode, which may result in unwanted results in your program.

But if you make your class immutable and then use it in such Data structures it will work more accurately.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store