As you already know, it's a great pattern for multithreading.
It also means much better encapsulation. You can pass those objects around and share them and you never, ever have to worry that someone changes your object's state.
There are some great examples in Java core library. Number subclasses are one, but I think the best example is String
. You pass them around, concatenate, get substrings etc. and never need to think about other places. If it was mutable like C/C++ char[]
, you would always need to keep that in mind.
For the same reason it also leads to more readable and maintainable code. No need to care about other users of the object.
Both these reasons lead us to another important pattern called Value Object. In brief, it makes sense when you care about some particular value (a date, a number, a string, an interval, money, or some slightly more complex objects if you need), but the value itself has no identity, i.e. it has exactly the same meaning regardless of context.