Memra

Sorting, choosing the right structure, and fail-fast iterators

Comparable vs Comparator, chained comparators, a Big-O cheat-sheet, and the ConcurrentModificationException trap.

Sorting with Comparable and Comparator

Comparable<T> is implemented by the element's own class to define its natural order:

public class Student implements Comparable<Student> {
    String name;
    int gpa;

    @Override
    public int compareTo(Student other) {
        return Integer.compare(this.gpa, other.gpa); // ascending by GPA
    }
}

List<Student> roster = new ArrayList<>(...);
Collections.sort(roster);  // uses natural order

Comparator<T> is a separate strategy object used when you don't own the class, or need a different order:

// Sort students by name, then by GPA descending
Comparator<Student> byNameThenGpa =
    Comparator.comparing(Student::getName)
              .thenComparing(Comparator.comparingInt(Student::getGpa).reversed());

roster.sort(byNameThenGpa);
// or: Collections.sort(roster, byNameThenGpa);

Quick Big-O guide for choosing a collection

| Need | Best choice | Key reason | |---|---|---| | Fast index access | ArrayList | O(1) get | | Fast head/tail insert+remove | ArrayDeque | O(1) both ends | | Unique elements, fast lookup | HashSet | O(1) average | | Unique elements, sorted | TreeSet | O(log n), NavigableSet | | Key→value, fast lookup | HashMap | O(1) average | | Key→value, sorted keys | TreeMap | O(log n), NavigableMap | | Key→value, insertion order | LinkedHashMap | O(1), predictable |

Fail-fast iterators and ConcurrentModificationException

Most java.util collections use fail-fast iterators: they track a structural modification count (modCount). If the collection is modified while an iterator is active — other than through the iterator itself — the iterator throws ConcurrentModificationException:

List<String> list = new ArrayList<>(List.of("a", "b", "c"));
for (String s : list) {
    if (s.equals("b")) list.remove(s); // ConcurrentModificationException!
}

Safe removal patterns:

// Pattern 1: Iterator.remove()
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    if (it.next().equals("b")) it.remove(); // safe
}

// Pattern 2: removeIf (Java 8+, cleaner)
list.removeIf(s -> s.equals("b")); // internally uses iterator safely

Never call the collection's own add/remove while inside a for-each loop over it.

NORMAL ~/memra/learn/java-from-zero/sorting-and-choosing utf-8 LF