Card 07/ 08

ExerciseDifficulty: Advanced1 min

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.

java
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?
Each signature, whether it survives, and what it commits to
SignatureSurvives?What it says
a(ArrayList<String>)NoDemands one class, and refuses List.of too
b(List<String>)YesNeeds order and positions, and accepts every list
c(Collection<String>)YesNeeds only to walk it: the widest honest type
d(HashSet<String>)NoDemands one class, so a TreeSet is refused
e() returning ListYesCallers cannot depend on which list it is
f() returning ArrayListCompiles, and traps youEvery 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.