I am learning the concept of immutability.
I understand that immutable objects cannot change their values once the object is created.
But I didn't understand the following uses of immutable objects.
They are
are automatically thread-safe and have no synchronization issues. How ? Proof ?
do not need a copy constructor. How ? Any example ?
do not need an implementation of clone How ? Any example ?
do not need to be copied defensively when used as a field How ? Any example ?
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. How ? Any example ?
Could someone please explain each of these points in detail with examples supporting it ?
Thanks.
解决方案
..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 Strings.
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 validStatuses;
static {
validStatuses = new ArrayList();
validStates.add(Status.OPEN);
validStates.add(Status.REOPENED);
validStates.add(Status.CLOSED);
}
This list was returned from a method:
public static List getAllStatuses() {
return validStates;
}
I retrieved that list but only wanted to show the open states in the interface:
List 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 validStatuses =
ImmutableList.of(Status.OPEN, Status.REOPENED, Status.CLOSED);
Then when I did something dumb:
List 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.