What makes a Java class immutable, and what are the rules you have to follow?
A class is immutable if its state cannot change after construction — if, once created, it is guaranteed to be the same for the whole of its life. That is stronger than merely having no setters, and the rules are specific.
First, the class must be final or its state-providing methods must be final. Otherwise a subclass could override a getter and change the behaviour, so a caller holding the parent type would get different values depending on the runtime type. Second, all the fields must be final, which is what the compiler uses to guarantee the values are published safely to other threads. Third, the constructor must set the fields and must not leak the reference to a partially built object — meaning no calling an overridable method from the constructor.
Fourth, and this is the one people forget, the fields must not refer to mutable objects unless those references are defensively copied. A final field holding a mutable List is not immutable, because anyone holding the List can change what the object contains.
Two consequences follow. An immutable object needs no synchronisation when shared between threads, because there is nothing to protect. And because its hash code cannot change, it is safe to use as a map key and to cache inside a hash-based set.