Immutable Class

Immutable class?

What is an immutable object?

An immutable object is one that will not change state after it is instantiated.

How to make an object immutable?

In general, an immutable object can be made by defining a class which does not have any of its members exposed, and does not have any setters.

The following class will create an immutable object:

class ImmutableInt {
private final int value;

public ImmutableInt(int i) {
value = i;
}

public int getValue() {
return value;
}
}

As can be seen in the above example, the value of the ImmutableInt can only be set when the object is instantiated, and by having only a getter (getValue) the object's state cannot be changed after instantiation.

However, there must be care taken that all objects that are referenced by the object must be immutable as well, or it could be possible to change the state of the object.

For example, allowing an reference to an array or ArrayList to be obtained through an getter will allow the internal state to change by changing the array or collection:

class NotQuiteImmutableList<T> {
private final List<T> list;

public NotQuiteImmutableList(List<T> list) {
// creates a new ArrayList and keeps a reference to it.
this.list = new ArrayList(list);
}

public List<T> getList() {
return list;
}
}

The problem with the above code is, that the ArrayList can be obtained through getList and be manipulated, leading to the state of the object itself to be altered, therefore, not immutable.

// notQuiteImmutableList contains "a", "b", "c"
List<String> notQuiteImmutableList= new NotQuiteImmutableList(Arrays.asList("a", "b", "c"));

// now the list contains "a", "b", "c", "d" -- this list is mutable.
notQuiteImmutableList.getList().add("d");

One way to get around this problem is to return a copy of an array or collection when called from a getter:

public List<T> getList() {
// return a copy of the list so the internal state cannot be altered
return new ArrayList(list);
}

What is the advantage of immutability?

The advantage of immutability comes with concurrency. It is difficult to maintain correctness in mutable objects, as multiple threads could be trying to change the state of the same object, leading to some threads seeing a different state of the same object, depending on the timing of the reads and writes to the said object.

By having an immutable object, one can ensure that all threads that are looking at the object will be seeing the same state, as the state of an immutable object will not change.

Why do we need immutable class?

The other answers seem too focused on explaining why immutability is good. It is very good and I use it whenever possible. However, that is not your question. I'll take your question point by point to try to make sure you're getting the answers and examples you need.

I am unable to get what are the scenarios where we need an immutable class.

"Need" is a relative term here. Immutable classes are a design pattern that, like any paradigm/pattern/tool, is there to make constructing software easier. Similarly, plenty of code was written before the OO paradigm came along, but count me among the programmers that "need" OO. Immutable classes, like OO, aren't strictly needed, but I going to act like I need them.

Have you ever faced any such requirement?

If you aren't looking at the objects in the problem domain with the right perspective, you may not see a requirement for an immutable object. It might be easy to think that a problem domain doesn't require any immutable classes if you're not familiar when to use them advantageously.

I often use immutable classes where I think of a given object in my problem domain as a value or fixed instance. This notion is sometimes dependent on perspective or viewpoint, but ideally, it will be easy to switch into the right perspective to identify good candidate objects.

You can get a better sense of where immutable objects are really useful (if not strictly necessary) by making sure you read up on various books/online articles to develop a good sense of how to think about immutable classes. One good article to get you started is Java theory and practice: To mutate or not to mutate?

I'll try to give a couple of examples below of how one can see objects in different perspectives (mutable vs immutable) to clarify what I mean by perspective.

... can you please give us any real example where we should use this pattern.

Since you asked for real examples I'll give you some, but first, let's start with some classic examples.

Classic Value Objects

Strings and integers are often thought of as values. Therefore it's not surprising to find that String class and the Integer wrapper class (as well as the other wrapper classes) are immutable in Java. A color is usually thought of as a value, thus the immutable Color class.

Counterexample

In contrast, a car is not usually thought of as a value object. Modeling a car usually means creating a class that has changing state (odometer, speed, fuel level, etc). However, there are some domains where it car may be a value object. For example, a car (or specifically a car model) might be thought of as a value object in an app to look up the proper motor oil for a given vehicle.

Playing Cards

Ever write a playing card program? I did. I could have represented a playing card as a mutable object with a mutable suit and rank. A draw-poker hand could be 5 fixed instances where replacing the 5th card in my hand would mean mutating the 5th playing card instance into a new card by changing its suit and rank ivars.

However, I tend to think of a playing card as an immutable object that has a fixed unchanging suit and rank once created. My draw poker hand would be 5 instances and replacing a card in my hand would involve discarding one of those instance and adding a new random instance to my hand.

Map Projection

One last example is when I worked on some map code where the map could display itself in various projections. The original code had the map use a fixed, but mutatable projection instance (like the mutable playing card above). Changing the map projection meant mutating the map's projection instance's ivars (projection type, center point, zoom, etc).

However, I felt the design was simpler if I thought of a projection as an immutable value or fixed instance. Changing the map projection meant having the map reference a different projection instance rather than mutating the map's fixed projection instance. This also made it simpler to capture named projections such as MERCATOR_WORLD_VIEW.

How to Create Immutable Class with ListString Element in class

this.courses = Collections.unmodifiableList(courses);

That creates, as the name says, an unmodifiable list. But that is just a view on the original list. Thus changes to that original list become visible in your "unmodifiable" view.

When in doubt: clone your list, like:

this.courses = new ArrayList<>(courses);

And then ensure that your getter does:

return Collections.unmodifiableList(courses);

Can you change a immutable class?

In object-oriented and functional programming, an immutable object
(unchangeable object) is an object whose state cannot be modified
after it is created. This is in contrast to a mutable object
(changeable object), which can be modified after it is created. In
some cases, an object is considered immutable even if some internally
used attributes change, but the object's state appears unchanging from
an external point of view. - WikiPedia

Immutable objects are thus instances whose state doesn’t change after they have been initialized. These types of classes are generally good for applications that need to implement some form of caching and where you are worried about thread-safety in a multi-threaded environment (immutable objects are inherently thread-safe).

I don't see your Car class, but assuming it'll look something like this:

public final class Car { 

final String registration;
final String owner;

public Car(String registration, String owner) {
this.registration = registration;
this.owner= owner;
}

public String getRegistration() {
return registration;
}

public String getOwner() {
return owner;
}
}

... notice that there are no setter methods in this class. Hence a car can only be initialized (i.e Car myCar = new Car("abcd", "John"); and the variables in them (namely, registration and owner) can never be updated.

So your changeOwner method is essentially looping through the instances of car in your garage and when it finds a matching registration number it removes that instance of car from your garage and then adds a whole new one.

To demonstrate this, you can run the following:

public class Garage {

public static void main(String ... args) {
List<Car> myGarage = new ArrayList<>();
myGarage.add(new Car("CG404GH", "John"));
System.out.println(myGarage);
for(Car car : myGarage) {
if("CG404GH".equals(car.getRegistration())) {
myGarage.remove(car);
Car updateCar = new Car("DD404GH", "John");
myGarage.add(updateCar);
}
}
System.out.println(myGarage);
}

}

This would print out something similar to the following (the portion after the @ would be different on each run):

[Car@4411d970]
[Car@6442b0a6]

The important thing to notice here is that the value after the @ are different, hence they are two completely different classes (instances) of car

How can we maintain Immutability of a class with a mutable reference

Well, the concept is reading the JLS and understanding it. Chapter 17 of the JLS "Threads and Locks" describes memory visibility and synchronization. Section 17.5 "Final Field Semantics" describes the memory visibility semantics for final fields. That section says in part:

final fields also allow programmers to implement thread-safe immutable objects without synchronization. A thread-safe immutable object is seen as immutable by all threads, even if a data race is used to pass references to the immutable object between threads. This can provide safety guarantees against misuse of an immutable class by incorrect or malicious code. final fields must be used correctly to provide a guarantee of immutability.

The usage model for final fields is a simple one: Set the final fields for an object in that object's constructor; and do not write a reference to the object being constructed in a place where another thread can see it before the object's constructor is finished. If this is followed, then when the object is seen by another thread, that thread will always see the correctly constructed version of that object's final fields. It will also see versions of any object or array referenced by those final fields that are at least as up-to-date as the final fields are.

So you need to:

  1. Make address both final and private.
  2. For any mutable object, you must prevent the reference to that object from being seen externally.

In this case, #2 probably means you can't return a reference to Address like you have with getAddress(). And you have to make a defensive copy in the constructor. I.e., make a copy of any mutable parameter, and store the copy in Employee. If you can't make a defensive copy, there's really no way to make Employee immutable.

public final class Employee{
private final int id;
private final Address address;
public Employee(int id, Address address)
{
this.id = id;
this.address=new Address(); // defensive copy
this.address.setStreet( address.getStreet() );
}
public int getId(){
return id;
}
public Address getAddress() {
Address nuAdd = new Address(); // must copy here too
nuAdd.setStreet( address.getStreet() );
return nuAdd;
}

Implementing clone() or something similar (a copy ctor) would make creating defensive objects easier for complicated classes. However, the best recommendation I think would be to make Address immutable. Once you do that you can freely pass around its reference without any thread-safety issues.

In this example, notice I do NOT have to copy the value of street. Street is a String, and strings are immutable. If street consisted of mutable fields (integer street number for example) then I would have to make a copy of street also, and so on ad infinitum. This is why immutable objects are so valuable, they break the "infinite copy" chain.

Since this question is getting popular, I should also add a mention of Brian Goetz's book, Java Concurrency in Practice, which is how I learned about these techniques, and I'm basically paraphrasing that book above.

Immutable Classes and Subclasses

If you want to enforce immutability, you cannot have subclasses.

This is almost true, but not entirely. To restate it:

If you want to enforce immutability, you must ensure that all sub-classes are immutable.

The problem with allowing subclassing is that normally anyone who can author a class can subclass any public non-final class.

But all subclasses must invoke one of their super-class's constructors. Package-private constructors can only be invoked by subclasses in the same package.

If you seal packages so that you control which classes are in your package, you can constrain subclassing. First define a class you want to subclass:

public abstract class ImmutableBaseClass {
ImmutableBaseClass(...) {
...
}
}

Since all sub-classes have to have access to the super-constructor, you can ensure all the sub-classes in the package you define follow immutable discipline.

public final class ImmutableConcreteClass extends ImmutableBaseClass {
public ImmutableConcreteClass(...) {
super(...);
}
}

To apply this to your example,

public abstract class Employee {
private final Id id;
private final Name name;

// Package private constructor in sub-classable class.
Employee(Id id, Name name, ...) {
// Defensively copy as necessary.
}
}

public final class Accountant extends Employee {
// Public constructos allowed in final sub-classes.
public Accountant(Id id, Name name, ...) {
super(id, name, ...); // Call to super works from same package.
}
}

public final class ITWorker extends Employee {
// Ditto.
public ITWorker(Id id, Name name, ...) {
super(id, name, ...);
}
}

Stored area of immutable classes

In recent interview, I was asked if string is stored in string-pool, as it supports immutability then where are our custom immutable classes are stored in java.

This is a nonsensical question with a wrong premise. Strings are not “stored in string-pool”, they are stored in the heap, like any other object. That’s a kind of tautology, as the heap memory is precisely defined as “The heap is the run-time data area from which memory for all class instances and arrays is allocated.

The string pool can be seen as containing strings, just like a Collection may contain objects, but in either case, it’s just holding references to objects. So a string contained in the pool still is stored in the heap memory, by definition, while the pool has a reference to it.

But the interviewer kept arguing that - If String has string-pool, can immutable classes also have some concept like that?

That’s an entirely different question. Of course, you can implement a pool of objects, as the Collection analogy above already indicated. Like strings contained in the pool are still stored in the heap memory, objects of your class are still stored in the heap memory when being referenced by whatever data structure used for the pool is referencing them. It’s not even necessary for the object to be immutable, to have such a pool, but the implied sharing of instances would cause semantic problems when mutations are possible. So creating a pool usually only makes sense for immutable objects.

For example, lots of the wrapper classes have such sharing, the valueOf methods for Short, Integer and Long will return shared instances for values in the -128 … +127 range and implementations are allowed to share even more, whereas Byte and Boolean return shared instances for all possible values.

However, there are reasons why not every immutable class implements a pool for all of its values:

  • If there is a large value space, you have to consider supporting garbage collection of unused objects, even when referenced by the pool
  • You have to consider the thread safety of your pool
  • Both points above may lead to a complex solution with a performance penalty that you don’t want to pay when the object is only used for a short time, as sharing only reduces memory consumption for long living objects

This applies to the existing examples as well. The wrapper objects only provide shared objects for a limited value space. Which are preallocated and never GCed. The string pool on the other hand, is dynamic, thread safe and supports garbage collection of its elements, which is the reason why intern() is not a cheap operation and should not be applied on every string. Instead, the pool is primarily used for constants, which are indeed long-living.



Related Topics



Leave a reply



Submit