Collections, equality, and order
Hash contracts, comparators, collection choice, and mutation ownership
Choose the semantics before the container
List preserves positions and duplicates. Set models uniqueness. Map associates one value with each key. ArrayList gives O(1) indexed reads and amortized append; removing from the middle shifts elements. ArrayDeque supports queue/stack ends without LinkedList's per-node allocation. HashMap/HashSet provide expected O(1) lookup, while TreeMap/TreeSet order by a comparator in O(log n). Hash iteration order is not a public contract.
equals must be reflexive, symmetric, transitive, and consistent. Equal objects must have equal hash codes; unequal objects may collide. A mutable field used by hashCode can strand a key after insertion because its bucket was chosen using an earlier value. Immutable records make good keys when all components have stable equality. Arrays in a record still compare by reference unless you design an alternative representation.
record Coordinate(int x, int y) {}
var counts = new HashMap<Coordinate, Integer>();
counts.put(new Coordinate(1, 2), 3);
assert counts.get(new Coordinate(1, 2)) == 3;Ordering has its own equality rule
A comparator returning zero makes two keys equivalent to an ordered set/map even when equals disagrees. Include tie-breakers when every logical key must survive. Use Integer.compare or comparingLong rather than subtraction, which may overflow. String.compareTo orders UTF-16 units; a different Unicode ordering must be explicit.
Comparator<String> order = Comparator.comparingInt(String::length)
.thenComparing(Comparator.naturalOrder());
assert order.compare("ab", "cd") < 0;Collection factories differ: List.of rejects null and is unmodifiable; Arrays.asList is fixed-size but permits set; an unmodifiable view can still reflect changes in its backing collection. List.copyOf creates an unmodifiable shallow snapshot. Iterating while structurally mutating a typical collection can fail fast, but ConcurrentModificationException is a diagnostic, not synchronization. Keep ownership boundaries explicit and sort output when deterministic order matters.
Put it into practice
Implement the exercise in a full-screen workspace, then run its tests.