Why Do We Need Immutable Class

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.

Why is it said that we dont need to clone an immutable class?

If you already have an object of an immutable class, there's no point in having a second functionally identical one also, you can just use the one instance everywhere. Also if would you clone it, you would just use twice as much memory for no extra gain.

Why would one declare an immutable class final in Java?

If you don't mark the class final, it might be possible for me to suddenly make your seemingly immutable class actually mutable. For example, consider this code:

public class Immutable {
private final int value;

public Immutable(int value) {
this.value = value;
}

public int getValue() {
return value;
}
}

Now, suppose I do the following:

public class Mutable extends Immutable {
private int realValue;

public Mutable(int value) {
super(value);

realValue = value;
}

public int getValue() {
return realValue;
}
public void setValue(int newValue) {
realValue = newValue;
}

public static void main(String[] arg){
Mutable obj = new Mutable(4);
Immutable immObj = (Immutable)obj;
System.out.println(immObj.getValue());
obj.setValue(8);
System.out.println(immObj.getValue());
}
}

Notice that in my Mutable subclass, I've overridden the behavior of getValue to read a new, mutable field declared in my subclass. As a result, your class, which initially looks immutable, really isn't immutable. I can pass this Mutable object wherever an Immutable object is expected, which could do Very Bad Things to code assuming the object is truly immutable. Marking the base class final prevents this from happening.

Hope this helps!

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 final keyword is necessary for immutable class?

As stacker says, final makes sure the class isn't subclassed. That's important so that any code which is relying on its immutability can do so safely.

For example, immutable types (where each field is also of an immutable type) can be freely used between threads without worrying about data races etc. Now consider:

public class Person {
private final String name;

public Person(String name) {
this.name = name;
}

public String getName() {
return name;
}
}

That looks like you can share Person instances freely across threads with no problem. But what about when the object you're sharing is actually a mutable subclass:

public class Employee extends Person {
private String company;

public Employee(String name, String company) {
super(name);
this.company = company;
}

public void setCompany(String company) {
this.company = company;
}

public String getCompany() {
return company;
}
}

Now instances of Employee aren't safe to share between threads, because they're not immutable. But the code doing the sharing may only know about them as instances of Person... leading them into a false sense of security.

The same goes for caching - it should be safe to cache and reuse immutable types, right? Well, it is safe to cache instances which are genuinely of an immutable type - but if you're dealing with a type which itself doesn't allow mutation, but does allow subclasses, it's suddenly not safe any more.

Think about java.lang.Object. It doesn't have any mutable fields, but it's clearly a bad idea to treat every Object reference as if it's a reference to an immutable type. Basically it depends on whether you think about immutability as a property of the type or of objects. A truly immutable type declares "any time you see a reference of this type, you can treat it as immutable" - whereas a type which allows arbitrary subclassing can't make that claim.

As an aside, there's a half-way house: if you can limit the subclassing to only "trusted" places, you can ensure that everything's immutable, but still allow that subclassing. The access in Java makes that tricky, but in C# for example you could have a public class which only allowed subclassing within the same assembly - giving a public API which is nice and strong in terms of immutability, while still allowing for the benefits of polymorphism.

Why we need mutable classes?

You need mutable classes to deal with situations when transforming a class from state A to state Z would produce a lot of intermediate objects, which you would rather not spend time creating.

One classic example is concatenating an array of strings. Let's say that you need to concatenate 100 strings, and produce a single result. Without a mutable string, you would need to produce 98 intermediate objects that would become eligible for garbage collection almost immediately. This is rather wasteful on the CPU, making a mutable object the right solution.

There are other situations when mutable objects are desirable. For example passing mutable objects into methods lets you collect multiple results without jumping through too many syntactic hoops. Another example is sorting and filtering: of course, you could make a method that takes the original collection, and returns a sorted one, but that would become extremely wasteful for larger collections.

Performance of programs using immutable objects

When you repeatedly modify a mutable object, it will likely produce less garbage than repeatedly constructing new immutable objects to represent the intermediate state. But there are several reasons why using immutable objects still is not necessarily imposing a performance problem:

  • In typical applications, this scenario occurs only occasionally, compared to other uses where immutable objects do not suffer or even turn out to win. Most notably:

    • getters do not need to create a defensive copy when returning an immutable object
    • setters can store the incoming argument by reference if immutable
    • verification methods can be implemented the simple (or naïve) way, without having to deal with the check-then-act problem, as immutable objects can not change between the check and the subsequent use
    • immutable objects can be safely shared, to actually reduce the amount of created objects or used memory
  • The impact of garbage collection to the performance is often overestimated. We routinely use the immutable type java.lang.String, benefitting from the advantages mentioned above. Strings are also one of the most often used hash map keys.

    There’s the mutable companion class StringBuilder for the scenario of repeated string manipulations, but its main advantage is not about the number of allocated objects. The problem with string construction is that each object has to create a copy of the contained characters, so operations like repeatedly concatenating characters lead to a quadratic time complexity when constructing a new string on each step. The StringBuilder still reallocates its buffer under the hood when necessary but with a nonlinear growth, which yields an amortized linear time complexity for repeated concatenation.

    As explained in this answer, the costs of garbage collection mainly depend on the still existing objects, so temporary objects usually do not impact the garbage collection much unless you create an excessive amount of them. But even the latter scenario should only be addressed if you have an actual performance problem and an impartial profiling tool proves that a particular allocation site truly is the culprit.

  • Sophisticated applications may have to deal with undo/redo or other versioning features, which require keeping copies of the alternative application state anyway. At this point, using immutable objects may actually become an advantage, as you do not need to copy objects which did not change between two versions of the application state. A changed application state may consist 99% of the same objects as the previous state.

  • One of the big reasons why the topic has become popular (again) is that immutable objects provide the easiest way to implement efficient and correct parallel processing. There is no need to acquire a lock to prevent inconsistent modifications. As said above, there’s no need to worry about the check-then-act problem. Further, when the application state can be expressed as a single reference to a compound immutable object, the check for a concurrent update reduces to a simple reference comparison. Compare also with this answer.

So there are a lot of performance advantages with immutable objects which may compensate the disadvantages, if there are any. At the same time, potential bottlenecks can be fixed with the established solution of temporarily dealing with mutable objects for an operation while keeping the overall immutable behavior.

Why we should use immutable classes provided by Java as key elements in a Map

You for a key is that its methods Object::hashCode & Object::equals shall not change over time otherwise the map will not be able to find the data back.

So if you use a mutable type AND you actually change the key while the data is in the map, then the data will not be found again.

You can put mutable data as key in a map just fine as long as they are not mutated while inside the map. But as a best practice it is better to put immutable data structure as key as to limit the risks of bugs occuring.

Downsides to immutable objects in Java?

But, what are the downsides to
favouring immutable objects in Java?
incompatibility with ORM or web
presentation tools?

Reflection based frameworks are complicated by immutable objects since they requires constructor injection:

  • there are no default arguments in Java, which forces us to ALWAYS provide all of the necessary dependencies
  • constructor overriding can be messy
  • constructor argument names are not usually available through reflection, which forces us to depend on argument order for dependency resolution

Implementation complexities?

Creating immutable objects is still a boring task; the compiler should take care of the implementation details, as in groovy

Is it possible to design a large-scale system (deep object graph) that predominately uses immutable objects?

definitely yes; immutable objects makes great building blocks for other objects (they favor composition) since it's much easier to maintain the invariant of a complex object when you can rely on its immutable components. The only true downside to me is about creating many temporary objects (e.g. String concat was a problem in the past).



Related Topics



Leave a reply



Submit