Before this lesson
Understand classes, objects and methods, and iterate over arrays.
What you will be able to do
Choose collection structures and produce deterministic summaries.
Understand the mechanism
List holds ordered elements and permits duplicates; Map associates unique keys with values. Map<String,Integer> lets the compiler check key and value types, reducing runtime casts.
HashMap does not guarantee iteration order. For a report, copy entrySet into a list and explicitly sort by key. Deterministic output helps both readers and tests.
merge inserts the initial value for a missing key and calls a combining function for an existing key. Integer::sum accumulates repeated courses. List.of returns an unmodifiable list that cannot be appended to.
Runnable example
Use JDK 21. Save Main.java in a separate practice directory, compile with javac -encoding UTF-8 Main.java, then run java Main. Each lesson is independent; do not combine multiple public Main classes.
import java.util.*;
public class Main {
public static void main(String[] args) {
List<String> courses = List.of("Python", "Java", "Python");
Map<String, Integer> counts = new HashMap<>();
for (String course : courses) counts.merge(course, 1, Integer::sum);
List<Map.Entry<String, Integer>> entries = new ArrayList<>(counts.entrySet());
entries.sort(Map.Entry.comparingByKey());
for (var entry : entries) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
}
Trace and verify
Java sorts first with count 1; Python has count 2. The source list retains duplicates while the map contains two keys.
Common mistakes and boundaries
Do not casually modify a collection structurally while iterating over it. Large counts may exceed Integer range and require different types and constraints.
Practice challenge
Add SQL twice and sort by descending count, then ascending course name.
Reference solution and reasoning
Compare b.getValue() to a.getValue(), then keys ascending for ties. Use Integer.compare rather than subtraction. The result is Python:2, SQL:2, Java:1.