Card 07/ 08
Practice: Which Declarations Survive Swapping the Implementation
Six signatures, and whether each still compiles when ArrayList becomes LinkedList or HashSet becomes TreeSet.
A declaration that names an interface survives a change of implementation; one that names a class does not. For each of the six signatures below, decide whether it still works when the caller switches from an ArrayList to a LinkedList, or from a HashSet to a TreeSet. Write all six down first.
void a(ArrayList<String> refs) { }
void b(List<String> refs) { }
void c(Collection<String> refs) { }
void d(HashSet<String> refs) { }
List<String> e() { return new ArrayList<>(); }
ArrayList<String> f() { return new ArrayList<>(); }Which of the six survive the swap, and what each one costs?
| Signature | Survives? | What it says |
|---|---|---|
a(ArrayList<String>) | No | Demands one class, and refuses List.of too |
b(List<String>) | Yes | Needs order and positions, and accepts every list |
c(Collection<String>) | Yes | Needs only to walk it: the widest honest type |
d(HashSet<String>) | No | Demands one class, so a TreeSet is refused |
e() returning List | Yes | Callers cannot depend on which list it is |
f() returning ArrayList | Compiles, and traps you | Every caller may now depend on it being an ArrayList |
The last row is the one to argue about. Returning the class does not break anything today; it publishes the choice, so changing it later becomes a change for everyone who calls you.
The rule underneath all six: declare the least you need. A method that only walks its argument should say Collection, and a method that indexes it should say List.
← → move through sections and cards