..are automatically thread-safe and have no synchronization issues
Concurrency problems happen when two different threads modify the state of the same object. Immutable objects can't be modified, so no problems.
Example: A String
. Two threads can be passed the same String
without worry since neither can mutate it in any way.
do not need a copy constructor
... because copy is the only way to mutate it. One common design pattern for immutable objects for every "modification" operation to make a copy and then perform the operation on the new object.
Copy constructors are usually used on objects that you want to change without affecting the original. This is always the case (by definition) with immutable objects.
In the case of String
, all the methods and the +
operator return new String
s.
do not need an implementation of clone
see above.
do not need to be copied defensively when used as a field
Once upon a time I did something silly. I had a set of enums in a List:
private static final List<Status> validStatuses;
static {
validStatuses = new ArrayList<Status>();
validStates.add(Status.OPEN);
validStates.add(Status.REOPENED);
validStates.add(Status.CLOSED);
}
This list was returned from a method:
public static List<Status> getAllStatuses() {
return validStates;
}
I retrieved that list but only wanted to show the open states in the interface:
List<Status> statuses = Status.getAllStatuses();
statuses.remove(Status.CLOSED);
Great, it worked! Wait, now all status lists are showing only those two -- even after page refresh! What happened? I modified a static object. Oops.
I could have used defensive copying on the return object of getAllStatuses
. Or, I could use something like Guava's ImmutableList in the first place:
private static final List<Status> validStatuses =
ImmutableList.of(Status.OPEN, Status.REOPENED, Status.CLOSED);
Then when I did something dumb:
List<Status> statuses = Status.getAllStatuses();
statuses.remove(Status.CLOSED); // Exception!
always have "failure atomicity" (a term used by Joshua Bloch) : if an immutable object throws an exception, it's never left in an undesirable or indeterminate state.
Because the class can never be modified, all states emitted by modification are whole, qualified objects (because they cannot change, they must always be in a qualified state to be useful). An exception would not emit a new object and therefore you can never have an undesirable or indeterminate state.