Card 04/ 08
Why a private List Returned by a Getter Is Not private
The only method that adds to the log validates carefully, and the log has entries it never added.
private stops other code naming a field; it does not protect the object the field points at. A getter that returns a private list hands out its address, and the caller can then change the list without any of the class's methods running. Return a copy or an unmodifiable view instead.
The field is private. The only method that touches it validates carefully. An audit log has entries in it that no call to addEntry ever produced:
class Audit {
private final List<String> entries = new ArrayList<>();
void addEntry(String line) {
if (line.isBlank()) { throw new IllegalArgumentException(); }
entries.add(line);
}
List<String> entries() { return entries; }
}audit.entries().add("");
audit.entries().clear();Line 9 hands out the address of the list. private protected the variable, since nothing outside the class can point entries somewhere else, and it never protected the object that variable points at.
Hand out something the caller cannot use to reach back: a copy, or an unmodifiable view.
List<String> entries() { return List.copyOf(entries); }
// or, when a snapshot would be too expensive
List<String> entries() { return Collections.unmodifiableList(entries); }List.copyOf gives the caller their own list, which stays correct even if yours changes afterwards. The unmodifiable view is cheaper and is a window onto yours, so it reflects later changes and refuses to make any.
← → move through sections and cards