How to create immutable class in Java ?
An immmutable class is a class whose state can not be changed once its instance has been created. There are many immmutable classes in Java for e.g. String
class, Integer
class.
Benefits of using immmutable class:
- An immutable class is useful when you want to use object for caching purpose for e.g. in
HashSet
or key in aHashMap
because you don’t need to worry about the value changes. - An immutable class is inherently thread-safe.
- Immutable objects are very useful in concurrent applications as their state cannot be changed state, so they cannot be corrupted or in consistent state if changed by multiple threads.
To create immutable class in Java, follow these rules:
Class
should be declared asfinal
, so it can't be extended.Class
attributes should be declared asfinal
.Class
should not have any setter methods.- Make all
class
attributes private. - Make defensive copies of fields that are mutable and return those.
1) Example below shows a mutable class
In this example we are using setter method for setting the day attribute, but we should not provide settter method for day attribute as we are not supposed to change the day state.
// mutable class public final class MutableDay { private String day; public MutableDay(String day) { this.day = day; } public String getDay() { return this.day; } public void setDay(String day) { this.day = day; } public static void main(String[] args) { MutableDay day = new MutableDay("Monday"); System.out.println(day.getDay()); day.setDay("Tuesday"); System.out.println(day.getDay()); } }
Output :
Monday Tuesday
2) Example below shows how can we make above class immutable by removing setter method for day attribute
// immutable class public final class ImmutableDay { private final String day; public ImmutableDay(String day) { this.day = day; } public String getDay() { return this.day; } public static void main(String[] args) { ImmutableDay day = new ImmutableDay("Monday"); System.out.println(day.getDay()); } }
Output :
Monday
3) Example below shows a mutable class with List type attribute
In this example in getDays() we should not return original copy of days List
, as it can be modifled by someone. Also you should not provide setter method for days List
as someone can modify the days List
.
import java.util.List; import java.util.ArrayList; // mutable class public final class MutableDay { private List<String> days; public MutableDay(List<String> days) { this.days = days; } public List<String> getDays() { return this.days; } public void setDays(List<String> days) { this.days = days; } public static void main(String[] args) { List<String> days = new ArrayList<String>(); days.add("Monday"); days.add("Tuesday"); days.add("Wednesday"); MutableDay day = new MutableDay(days); days = day.getDays(); System.out.println(days); days.remove("Wednesday"); System.out.println(day.getDays()); } }
Output :
[Monday, Tuesday, Wednesday] [Monday, Tuesday]
4) Example below shows how to make above class immutable by creating a copy of days List
when returning it and removing the setter method for days List
// immutable class import java.util.List; import java.util.ArrayList; public final class ImmutableDay { // immutable class should be final private final List<String> days; // immutable class attributes should be final public ImmutableDay(List<String> days) { this.days = days; } // return copy of days instead of actual data public List<String> getDays() { return new ArrayList<String>(this.days); } public static void main(String[] args) { List<String> days = new ArrayList<String>(); days.add("Monday"); days.add("Tuesday"); days.add("Wednesday"); ImmutableDay day = new ImmutableDay(days); days = day.getDays(); System.out.println(days); days.remove("Wednesday"); System.out.println(day.getDays()); } }
Output :
[Monday, Tuesday, Wednesday] [Monday, Tuesday, Wednesday]
5) Example below shows a mutable class with Date type attribute.
In this example in getPublishedDate() method we should not return exact copy of publishedDate, as it can be modifled by someone.
import java.util.Date; // mutable class public final class MutableBook { private String bookName; private Date publishedDate; public MutableBook(String bookName, Date publishedDate) { this.bookName = bookName; this.publishedDate = publishedDate; } public String getBookName() { return this.bookName; } public Date getPublishedDate() { return this.publishedDate; } public static void main(String[] args) { MutableBook book = new MutableBook("Lord of the Rings" , new Date(1997, 10, 01)); System.out.println(book.getBookName()); Date publishedDate = book.getPublishedDate(); System.out.println("Actual published date " + publishedDate); publishedDate.setYear(2018); System.out.println("Modified published date " + book.getPublishedDate()); } }
Output :
Lord of the Rings Actual published date Mon Nov 01 00:00:00 IST 3897 Modified published date Fri Nov 01 00:00:00 IST 3918
6) Example below shows how to create immutable class in Java with Date
type attribute.
In this example we return a copy of publishedDate instead of returning the actual publishedDate instance. The caller of this method can't modify the original Date
object.
import java.util.Date; // immutable class public final class ImmutableBook { private String bookName; private Date publishedDate; public ImmutableBook(String bookName, Date publishedDate) { this.bookName = bookName; this.publishedDate = publishedDate; } public String getBookName() { return this.bookName; } public Date getPublishedDate() { return new Date(publishedDate.getTime()); } public static void main(String[] args) { ImmutableBook book = new ImmutableBook("Lord of the Rings" , new Date(1997, 10, 01)); System.out.println(book.getBookName()); Date publishedDate = book.getPublishedDate(); System.out.println("Actual published date " + publishedDate); publishedDate.setYear(2018); System.out.println("Modified published date " + book.getPublishedDate()); } }
Output :
Lord of the Rings Actual published date Mon Nov 01 00:00:00 IST 3897 Modified published date Mon Nov 01 00:00:00 IST 3897
References :
Oracle Docs Immutable objects
Oracle Docs String class