Card 04/ 08
All 8 cards
GotchaDifficulty: Intermediate1 min
Why Your private List Is Not private
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 — 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.