Sunday 2 April 2017

Immutability in Java

Immutable class plays very important role in Java programming and also you can expect questions on Immutability concept almost in every Java interview. 


1.What is Immutable class?

Answer: Immutable class is a special kind of class which is used to ensure that once you created an object and defined it's state, you can not modify the object's state. If you will try to modify, you should get a new object with your changes but original object and it's state will remain same.
So we can say that as per the concept of Immutability once you created an object and define it's state(values), you can not modify it further.

2.How to design an Immutable class ?

AnswerTo design an Immutable class we need to follow below steps:
1. Mark all member variable of class as private and final: Private because we are not going to allow direct access to member variables from outside the class, Final because we are not supposed to change the value of member variable once initialized.
Example: In below code we have an Immutable class Employee. We have marked class as final and variables are marked as private and final.
At line number 3 we have initialized our emp object and then at line number 7 and 8 we did some modification. If you run below code you will get same value printed for emp object in console both the time.
Reason behind for such behavior is that String, Integer etc. are inbuilt immutable class of Java. 
So if member variables are already immutable then you don't need to worry about their modification. 
Note : If you have reference variable of Mutable type(for example Date class) then you need to put extra care in your code.
2. There should be no setter method for member variables(only getter methods for access): This is because there is no need of setting values again once object is initialized via constructor.
3.Mark your class as Final: By marking class as Final we are restricting other classes from extending it. If other classes are allowed to extend immutable class, they can override functionalities which can break the immutability feature.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class TestMutability {
 public static void main(String[] args) {
  Employee emp = new Employee(1234, "John", 27);
  System.out.println("Employee details: "+emp.toString());
  String empName = emp.getEmpName();
  Integer empAge = emp.getEmpAge();
  empName = "Tom";
  empAge = 25;
  System.out.println("After modification");
  System.out.println("Employee details: "+emp.toString());
 }
}

final class Employee{
 final private Integer empId;
 final private String empName;
 final private Integer empAge;
 
 public Employee(Integer empId, String empName, Integer empAge) {
  this.empId = empId;
  this.empName = empName;
  this.empAge = empAge;
 }
 
 public Integer getEmpId() {
  return empId;
 }
 public String getEmpName() {
  return empName;
 }
 public Integer getEmpAge() {
  return empAge;
 }
 
 @Override
 public String toString(){
  return"Employee Id: " + empId + ", Employee Name: "+ empName + ", Employee Age: " + empAge;
 }
}
So we can say that if all your reference member variables are immutable and you have incorporated above three rules then your class will be an Immutable class. If you have mutable reference member variables then you need to take extra care of those reference member variable

Follow-up Question: How will you handle mutable reference variable scenario?

Answer:  In below code we have added joiningDate varaible in Employee class which is of Date type. Date is inbuilt mutable class in Java. At line number 41 inside getJoiningDate method where instead of returning actual object we are returning clone of it. So any modification in joiningDate variable at line number 9 won't impact original joiningDate of Employee class as we working on clone object.

If you run below code same value will get printed for joiningDate both the time in console even when we are modifying joiningDate at line 10. If you run the below code by removing the clone part and again(directly returning original object) you will notice the difference.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import java.util.Date;

public class TestMutability {
 public static void main(String[] args) {
  Employee emp = new Employee(1234, "John", 27);
  System.out.println("Employee details: "+emp.toString());
  String empName = emp.getEmpName();
  Integer empAge = emp.getEmpAge();
  Date joiningDate = emp.getJoiningDate();
  joiningDate.setDate(10);
  empName = "Tom";
  empAge = 25;
  System.out.println("After modification");
  System.out.println("Employee details: "+emp.toString());
 }
}

final class Employee{
 final Integer empId;
 final String empName;
 final Integer empAge;
 final Date joiningDate;
 
 public Employee(Integer empId, String empName, Integer empAge) {
  this.empId = empId;
  this.empName = empName;
  this.empAge = empAge;
  joiningDate = new Date();
 }
 
 public Integer getEmpId() {
  return empId;
 }
 public String getEmpName() {
  return empName;
 }
 public Integer getEmpAge() {
  return empAge;
 }
 public Date getJoiningDate() {
  return (Date)joiningDate.clone();
 }
 @Override
 public String toString(){
  return"Employee Id: " + empId + ", Employee Name: "+ empName + ", Employee Age: " + empAge+", Joining Date:"+joiningDate;
 }
}
So we can say that to handle mutable reference variable we shouldn't return original object instead we should return clone (or by creating new object) of original object.

3. How many object will get created in below codes and why?

1. 
1
2
3
4
5
6
public class StringExample {
 public static void main(String[] args) {
  String s1 = "Hello";
  String s2 = new String("Hello");
 }
}
Answer: Here 2 objects will get created : one object will get created at line 3 in String pool and at line 4 one more object will get created in Heap as we are using new keyword.
2.
1
2
3
4
5
6
public class StringExample {
 public static void main(String[] args) {
  String s1 = "Hello";
  String s2 = "Hello";
 }
}
Answer: In above code only 1 object will get created : one object will get created at line 3 in String pool and at line 4 object will not get created as "Hello" is already in String pool.
3.
1
2
3
4
5
6
public class StringExample {
 public static void main(String[] args) {
  String s1 = "Hello";
  String s2 = s1+"World";
 }
}
Answer: In above code 2 objects will get created : one object will get created at line 3 in String pool and one more object will get created at line 4 in String pool. Since String is immutable and we are trying to modify value of s1 which will result in new object as per immutability rules.
So final value of variables will be like as follow: Value of s1 will be "Hello" and Value of s2 will be "HelloWorld".
Note: There are two ways we can create String object which are as follows: 
1. String s1 = "Hello" - In this case object always create only in String pool if and only if there is no string constant with same value exist in pool otherwise same will use.
2. String s1 = new String("Hello") - In this case one object always create in Heap and second in String pool if and only if there is no string constant with same value exist in pool otherwise same will use.

No comments:

Post a Comment