Collections
Arrays have a fixed size set at creation — you cannot add or remove elements. Java's Collections Framework provides dynamic, type-safe data structures that grow as needed and offer powerful built-in operations.
The Collections Framework
The Java Collections Framework (JCF) is a set of interfaces and classes in java.util that provide standard, reusable implementations of common data structures. The three you will use most are:
- ArrayList — an ordered, resizable list (like a dynamic array).
- HashMap — an unordered map from keys to values (like a dictionary).
- HashSet — an unordered collection of unique values.
Generics
The <T> syntax in ArrayList<String> is a generic type parameter. It tells the compiler what type the collection holds, enabling compile-time type checking and eliminating the need for casting. Always specify the type — using a raw ArrayList without generics is a red flag in professional code.
ArrayList
import java.util.ArrayList;
import java.util.Collections;
ArrayList<String> learners = new ArrayList<>();
// Adding elements
learners.add("Thandi");
learners.add("Sipho");
learners.add("Lerato");
learners.add("Bongani");
learners.add(1, "Zanele"); // insert at index 1
System.out.println("Size: " + learners.size());
System.out.println("Get index 2: " + learners.get(2));
System.out.println("Contains Sipho: " + learners.contains("Sipho"));
System.out.println("Index of Lerato: " + learners.indexOf("Lerato"));
// Iterating
for (String name : learners) {
System.out.println(" " + name);
}
// Removing
learners.remove("Zanele"); // remove by value
learners.remove(0); // remove by index — careful not to confuse them for Integer lists
// Sorting
Collections.sort(learners); // alphabetical for Strings
System.out.println("Sorted: " + learners);
// Converting to array when needed
String[] arr = learners.toArray(new String[0]);
ArrayList of Objects
ArrayList<Learner> cohort = new ArrayList<>();
cohort.add(new Learner("Thandi", 21, "Java", 74.5));
cohort.add(new Learner("Sipho", 24, "Python", 81.0));
cohort.add(new Learner("Lerato", 20, "SQL", 68.0));
cohort.add(new Learner("Bongani", 22, "C#", 88.5));
// Compute statistics
double total = 0;
int passCount = 0;
for (Learner l : cohort) {
total += l.getMark();
if (l.getMark() >= 50) passCount++;
}
System.out.printf("Cohort average: %.1f%% | Pass rate: %d/%d%n",
total / cohort.size(), passCount, cohort.size());
// Sorting with a custom comparator (lambda — Lesson 17)
cohort.sort((a, b) -> Double.compare(b.getMark(), a.getMark())); // descending by mark
cohort.forEach(l -> System.out.printf("%-12s %.1f%%%n", l.getName(), l.getMark()));
HashMap
A HashMap stores key-value pairs. Looking up a value by key is O(1) on average — extremely fast regardless of how many entries there are. Keys must be unique; values can repeat.
import java.util.HashMap;
import java.util.Map;
HashMap<String, Double> marks = new HashMap<>();
// Adding entries
marks.put("Thandi", 74.5);
marks.put("Sipho", 81.0);
marks.put("Lerato", 68.0);
marks.put("Bongani", 88.5);
// Reading
System.out.println("Sipho's mark: " + marks.get("Sipho")); // 81.0
System.out.println("Has Thandi: " + marks.containsKey("Thandi")); // true
System.out.println("Has mark 99: " + marks.containsValue(99.0)); // false
// Safe get with default
double mark = marks.getOrDefault("Zanele", -1.0);
System.out.println("Zanele: " + mark); // -1.0 (not found)
// Iterating key-value pairs
for (Map.Entry<String, Double> entry : marks.entrySet()) {
System.out.printf("%-10s: %.1f%%%n", entry.getKey(), entry.getValue());
}
// Iterating only keys
for (String name : marks.keySet()) { System.out.println(name); }
// Iterating only values
for (double m : marks.values()) { System.out.println(m); }
// Removing
marks.remove("Bongani");
System.out.println("Size after removal: " + marks.size());
HashSet
A HashSet stores unique elements — duplicates are silently ignored. Use it when you care about membership rather than position or count.
import java.util.HashSet;
HashSet<String> courses = new HashSet<>();
courses.add("Java");
courses.add("Python");
courses.add("SQL");
courses.add("Java"); // duplicate — silently ignored
courses.add("C#");
System.out.println("Size: " + courses.size()); // 4 (not 5)
System.out.println("Has Java: " + courses.contains("Java")); // true
System.out.println("Has Kotlin: " + courses.contains("Kotlin")); // false
// Set operations (useful for comparisons)
HashSet<String> set1 = new HashSet<>(java.util.Arrays.asList("A","B","C","D"));
HashSet<String> set2 = new HashSet<>(java.util.Arrays.asList("C","D","E","F"));
HashSet<String> union = new HashSet<>(set1);
union.addAll(set2); // {A, B, C, D, E, F}
HashSet<String> intersection = new HashSet<>(set1);
intersection.retainAll(set2); // {C, D}
System.out.println("Union: " + union);
System.out.println("Intersection: " + intersection);
Practice Task
Your Turn
Build a CourseManager using collections: (1) an ArrayList<Learner> to hold all learners, (2) a HashMap<String, ArrayList<Learner>> that maps course names to lists of learners in that course, (3) a method enrol(Learner l, String course) that adds to both, (4) a method getCourseAverage(String course) that returns the average mark for a course, (5) a method topLearner() that finds the highest-scoring learner across all courses. Test with at least 8 learners across 3 courses.
Common Mistakes
- Removing an element by index vs by value from an
ArrayList<Integer>:list.remove(5)removes the element at index 5, butlist.remove(Integer.valueOf(5))removes the first occurrence of the value 5. - HashMap does not guarantee order — if you need insertion-order or sorted order, use
LinkedHashMaporTreeMap. - Using raw types (
ArrayListinstead ofArrayList<String>) — this compiles with warnings but loses all type safety. - Modifying an ArrayList while iterating over it with for-each — use an Iterator or remove by index in a reverse loop.
- Forgetting that HashSet uses hashCode() and equals() for uniqueness — custom objects need these overridden to work correctly in a HashSet.
Professional Tip
Collections are one of the most-used parts of the Java standard library. The patterns you learn here — putting objects into an ArrayList, grouping with a HashMap, deduplicating with a HashSet — appear in virtually every real Java application from web backends to Android apps.
Mini Quiz
What makes HashMap lookups very efficient?