Using some setters, without setting all needed properties in the constructor(s)
public final class Person { // example of a bad immutability
private final String name;
private final String surname;
public Person(String name) {
this.name = name;
}
public String getName() { return name;}
public String getSurname() { return surname;}
public void setSurname(String surname) { this.surname = surname); }
}
It’s easy to show that Person
class is not immutable:
Person person = new Person("Joe");
person.setSurname("Average"); // NOT OK, change surname field after creation
To fix it, simply delete setSurname()
and refactor the constructor as follows:
public Person(String name, String surname) {
this.name = name;
this.surname = surname;
}
Not marking instance variables as private and final
Take a look at the following class:
public final class Person {
public String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
The following snippet shows that the above class is not immutable:
Person person = new Person("Average Joe");
person.name = "Magic Mike"; // not OK, new name for person after creation
To fix it, simply mark name property as private
and final
.
Exposing a mutable object of the class in a getter
Take a look at the following class:
import java.util.List;
import java.util.ArrayList;
public final class Names {
private final List<String> names;
public Names(List<String> names) {
this.names = new ArrayList<String>(names);
}
public List<String> getNames() {
return names;
}
public int size() {
return names.size();
}
}
Names
class seems immutable at the first sight, but it is not as the following code shows:
List<String> namesList = new ArrayList<String>();
namesList.add("Average Joe");
Names names = new Names(namesList);
System.out.println(names.size()); // 1, only containing "Average Joe"
namesList = names.getNames();
namesList.add("Magic Mike");
System.out.println(names.size()); // 2, NOT OK, now names also contains "Magic Mike"
This happened because a change to the reference List returned by getNames()
can modify the actual list of Names
.