.. are automatically thread safe and have no synchronization problems
Problems
Concurrency occurs when two different threads change the state of the same object. Immutable objects cannot be modified, so no problem.
Example: A String . Two streams can be transmitted by the same String without problems, since none of them can mutate it.
no copy constructor required
... because a copy is the only way to mutate it. One common design pattern for immutable objects for each “modification” operation, to make a copy and then perform an operation on a new object.
Copy constructors are typically used for objects that you want to modify without affecting the original. This always takes place (by definition) with immutable objects.
In the case of String all methods and the + operator return a new String s.
no clone implementation required
see above.
no need to copy defensively when used as a field
I used to do something stupid. I had a list of listings 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 got this list, but wanted to show open states in the interface:
List<Status> statuses = Status.getAllStatuses(); statuses.remove(Status.CLOSED);
Great, it worked! Wait, now all the status lists show only those two - even after refreshing the page! What happened? I changed the static object. Unfortunately.
I could use protective copying on the returned getAllStatuses object. Or, I could use something like a Guava 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);
always has an “atomic failure” (a term used by Joshua Bloch): if an immutable object throws an exception, it never throws in an undesirable or undefined state.
Since the class can never be changed, all the states emitted by the modification are whole, qualified objects (because they cannot change, they must always be in a qualified state in order to be useful). An exception should not cause a new object, and therefore you can never have an unwanted or undefined state.