Examples of Immutable Classes

Complete List of immutable JDK classes?

I try to compile the list as much as I can:

  1. java.lang.String
    The wrapper classes for the primitive types:
  2. java.lang.Integer
  3. java.lang.Byte
  4. java.lang.Character
  5. java.lang.Short
  6. java.lang.Boolean
  7. java.lang.Long
  8. java.lang.Double
  9. java.lang.Float
  10. java.lang.StackTraceElement (used in building exception stacktraces)
  11. Most of the enum classes
  12. java.math.BigInteger
  13. java.math.BigDecimal
  14. java.io.File
  15. java.awt.Font
  16. java.awt.BasicStroke
  17. java.awt.Color
  18. java.awt.GradientPaint,
  19. java.awt.LinearGradientPaint
  20. java.awt.RadialGradientPaint,
  21. java.awt.Cursor
  22. java.util.Locale
  23. java.util.UUID
  24. java.util.Collections
  25. java.net.URL
  26. java.net.URI
  27. java.net.Inet4Address
  28. java.net.Inet6Address
  29. java.net.InetSocketAddress
  30. most subclasses of java.security.Permission

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.

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.

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, ...);
}
}

Practical example for Immutable class

Consider java.lang.String. If it weren't immutable, every time you ever have a string you want to be confident wouldn't change underneath you, you'd have to create a copy.

Another example is collections: it's nice to be able to accept or return a genuinely immutable collection (e.g. from Guava - not just an immutable view on a mutable collection) and have confidence that it won't be changed.

Whether those count as "needs" or not, I don't know - but I wouldn't want to develop without them.

Example of an immutable class with hashmap

Your test is wrong, you're checking the contents of h, the map that you passed to the constructor and later modified, instead of imm.getH(). If you check the proper map

for (Entry<String, String> entry : imm.getH().entrySet())
System.out.println(entry.getKey() + " --- " + entry.getValue());

things look just fine:

!am@John6
Info1 --- !am@John
Inf02 --- !amCrazy6

So your IamImmutable constructor is already fine, any later changes to the original map passed into the constructor won't affect the copy you made at construct time. You can also use the other HashMap constructor you mentioned, which is slightly more readable:

public IamImmutable(int i, String s, HashMap<String, String> h)
{
this.i = i;
this.s = s;
this.h = new HashMap<String, String>(h);
}

And that will work fine too.


A different problem is that getH() passes a reference to the internal map out to the world, and if the world changes that reference, things will go wrong. An easy way to get around that is to apply the same copy trick that you already use in the constructor in getH() as well:

public HashMap < String, String > getH() {
return new HashMap<String,String>(h);
}

Or to decorate the internal map before returning it:

public Map<String, String> getH() {
return Collections.unmodifiableMap(h);
}

Consider using the ImmutableCollections in the guava library instead. They've done the same job that this code is doing, but with a bit more thought to efficiency and ease of use. The full copies at construct time and to get the map are unwieldy and the standard underlying HashMap will do modification checks that are pointless if we know it isn't going to get modified anyways.

non final - immutable classes

If you can extend an immutable class (which means it's not final), you can add mutable properties to the sub-class, which would make your sub-class mutable, and therefore the base class would also be mutable, since it can have mutable sub-classes.



Related Topics



Leave a reply



Submit