The most common question you ever come round with in Java is :
“Why is String class called Immutable ?” ( No Offence Intended !!! )
Hold on… we are not going to answer this here, this is the first thing you are taught or you learn when encountering String for the first time.
We are here to get a step ahead and explore immutability.
So what is an immutable object ?
An immutable object is one whose visible state cannot change once instantiated.
The most common examples are String, Boolean, Byte, Character, Double, Float, Integer, Long, Short, String. in the Java class library.
What are the benefits of using an immutable object?
In order to understand the importance lets look into an example
If an object is mutable, you have to be cautious while using a reference to it.
Date today = new Date();
Scheduler.scheduleTask(todayTask, today);
today.setTime(d.getTime() + ONE_DAY); // change to tomorrow
scheduler.scheduleTask(tomorrowTask, today);
Because Date is mutable, the scheduleTask method must defensively copy the date parameter into its instance variables. Otherwise, todayTask and tomorrowTask might both execute tomorrow, which was not our intention. It is quiet common to forget the defensive copying of the date parameter when coding a method like scheduleTask()
Looking into another fact , when we send an object to a method as arguments we don’t expect the method to mutate the state of our objects, unless they are explicitly documented to do so or they are the actual owner of that object.But, with mutable objects you can just afford to have your fingers crossed and hope the method doesn’t break your trust.
How to create an immutable object
1.Strong Immutability – It prevents anyone from extending your class and accidentally or deliberately making it mutable.
2. Weak Immutability where you make your methods final. It allows others to extend your class to add more behaviour, but protects the original contract specified by the class(ONLY).
Protect your mutable fields
The last requirement which we already discussed earlier, is to protect the mutable attributes from manipulation.
To highlight this problem, we’ll use the example of a supposedly immutable class representing a person.
Say our class has a date of birth.
import java.util.Date;
public final class ImmutablePerson // atleast our assumption
{
private String firstName;
private String lastName;
private Date dob;
public ImmutablePerson(String firstName,String lastName, Date dob)
{
this.firstName = firstName;
this.lastName = lastName;
this.dob = dob;
}
public String getFirstName()
{
return this.firstName;
}
public String getLastName()
{
return this.lastName;
}
public Date getDob()
{
return this.dob;
}
}
//This all looks fine, until someone uses it like this:
Date newDate = new Date();
ImmutablePerson person =
new ImmutablePerson( "Dev", "Chatterjee", newDate );
System.out.println( person.getDob() );
newDate.setMonth( newDate.getMonth() + 1 );
System.out.println( person.getDOB() );
The Date object is mutable, and the person variable is referencing the same instance of the Date object as the newDate variable. When newDate changes the instance it is referencing, the person instance changes too. It is not immutable to our horror!
We can defend against this by taking a copy of the of the Date instance when it is passed in rather than trusting the reference to the instance we are given.
import java.util.Date;
public final class ImmutablePerson
{
private String firstName;
private String lastName;
private Date dob;
public ImmutablePerson( String firstName,
String lastName, Date dob)
{
this.firstName = firstName;
this.lastName = lastName;
this.dob = new Date( dob.getTime() );
}
Now we’re close, but we’re still not quite there. Our class is still open to abuse.
ImmutablePerson person = new ImmutablePerson( "Dev", "Chatterjee", new Date() );
System.out.println( person.getDob() );
Date myDate = person.getDob();
myDate.setMonth( myDate.getMonth() + 1 );
System.out.println( person.getDob() );
We see here that taking a copy on the way in wasn’t enough; we also need to prevent anyone from getting a reference to our mutable Date field when we pass it out.
public Date getDob()
{
return new Date( this.dob.getTime() ); // you can even clone the object and send it...
}
Similarly for Lists you can use Collection.unmodifiableList(yourList);
Also to make sure you are absolutely safe make deep copies of mutable data ….
So we wind up here
But that is not exactly the concept of immutability.For eg,internally a new String is created ,every time we try to modify it,but we are able to do.What We are doing in above code is that our class cannot be modified in any possible way but that is not how String works. 🙁 (Correct me If I am wrong)
@Garima – First of all thanks for reading the blog. Just to make the things a bit more clear, the blog is based on the internal concept of Immutability. The way String works is its own implementation. That can always be implemented in your code ! What matters is the fact that the actual object is not modified , and even that can be further implemented as Weak or Strong immutability. String implementation is the Strong immutability concept added to its implementation which gives you a new object every time you try modifying (Motive – prevent modification in the existing object).