Collections
advancedPart of Advanced Java
Theory
The Java Collections Framework (JCF) is a unified architecture for storing and manipulating groups of objects. It provides interfaces, implementations, and algorithms that make working with data structures convenient and efficient.
Collection Framework Overview
The framework is organized around core interfaces:
Collection (interface)
├── List (ordered, allows duplicates)
│ ├── ArrayList
│ └── LinkedList
├── Set (no duplicates)
│ ├── HashSet
│ └── TreeSet
└── Queue (FIFO)
└── PriorityQueue
Map (interface — separate from Collection)
├── HashMap
└── TreeMap
List — ArrayList and LinkedList
ArrayList is a resizable array implementation. It provides fast random access (O(1)) but slower insertions/deletions in the middle (O(n)).
LinkedList is a doubly-linked list. It provides fast insertions/deletions (O(1) at ends) but slower random access (O(n)).
import java.util.*;
List<String> arrayList = new ArrayList<>();
arrayList.add("Apple");
arrayList.add("Banana");
arrayList.add("Cherry");
System.out.println(arrayList.get(0)); // Apple
arrayList.set(1, "Blueberry");
arrayList.remove(2);
List<Integer> linkedList = new LinkedList<>();
linkedList.add(10);
linkedList.addFirst(5); // Only LinkedList has addFirst
linkedList.addLast(15);Set — HashSet and TreeSet
HashSet stores elements in a hash table. It offers O(1) operations but no guaranteed order.
TreeSet stores elements in a sorted tree structure (red-black tree). Operations are O(log n).
Set<String> hashSet = new HashSet<>();
hashSet.add("Java");
hashSet.add("Python");
hashSet.add("Java"); // Duplicate — ignored
System.out.println(hashSet.size()); // 2
Set<Integer> treeSet = new TreeSet<>();
treeSet.add(30);
treeSet.add(10);
treeSet.add(20);
System.out.println(treeSet); // [10, 20, 30] — sortedMap — HashMap and TreeMap
Maps store key-value pairs. Keys are unique; values can be duplicated.
HashMap offers O(1) lookup with no guaranteed order.
TreeMap maintains keys in sorted order (O(log n) operations).
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 95);
scores.put("Bob", 87);
scores.put("Charlie", 92);
System.out.println(scores.get("Alice")); // 95
System.out.println(scores.containsKey("Bob")); // true
// Iterate over entries
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}Generics
Generics provide type safety by allowing you to specify the type of elements a collection can hold:
// Without generics (old way) — unsafe
List list = new ArrayList();
list.add("Hello");
list.add(123); // No compile-time error
String s = (String) list.get(1); // ClassCastException at runtime!
// With generics — type safe
List<String> safeList = new ArrayList<>();
safeList.add("Hello");
// safeList.add(123); // Compile-time error!
String s = safeList.get(0); // No cast neededYou can also create your own generic classes:
public class Box<T> {
private T content;
public void set(T content) { this.content = content; }
public T get() { return content; }
}
Box<String> stringBox = new Box<>();
stringBox.set("Hello");
String value = stringBox.get();Iterating Collections
There are several ways to iterate over collections:
For-each loop (most common):
for (String item : list) {
System.out.println(item);
}Iterator (use when you need to remove elements during iteration):
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (item.startsWith("A")) {
iterator.remove(); // Safe removal
}
}Streams API (Java 8+):
list.stream()
.filter(s -> s.length() > 3)
.map(String::toUpperCase)
.forEach(System.out::println);Collections Utility Class
java.util.Collections provides static utility methods:
List<Integer> numbers = new ArrayList<>(Arrays.asList(3, 1, 4, 1, 5, 9));
Collections.sort(numbers); // [1, 1, 3, 4, 5, 9]
Collections.reverse(numbers); // [9, 5, 4, 3, 1, 1]
Collections.shuffle(numbers); // Random order
Collections.max(numbers); // 9
Collections.min(numbers); // 1
Collections.frequency(numbers, 1); // 2
Collections.binarySearch(numbers, 5); // index (list must be sorted first)Always use the interface type (List, Set, Map) for variable declarations, not the implementation type (ArrayList, HashSet, HashMap). This makes it easy to switch implementations later.
Practical Examples
When you need predictable iteration order, use LinkedHashMap or LinkedHashSet instead of HashMap/HashSet. They maintain insertion order with slightly more memory.
Exercises
List Operations
Write a program that creates an ArrayList of integers (1 through 10). Then: remove all even numbers, add the square of each remaining number, and sort the list in descending order.
Expected Output:
[81, 49, 25, 9, 1]Phone Directory with Map
Create a phone directory using a TreeMap that stores names (keys) and phone numbers (values). Implement methods: addContact, removeContact, findContact, and listAllContacts (sorted by name).
Expected Output:
Alice: 555-1234\nBob: 555-5678\nCharlie: 555-9012\nAlice: 555-1234Set Intersection and Union
Write a program that takes two arrays of integers, converts them to HashSet, and computes their union, intersection, and symmetric difference (elements in one set but not both).
Expected Output:
Union: [1, 2, 3, 4, 5, 6, 7, 8, 9]\nIntersection: [4, 5, 6]\nSymmetric Diff: [1, 2, 3, 7, 8, 9]Mini Quiz
Mini Quiz
Mini Project
Mini Project: Task Manager Application
Build a task manager that allows users to add, remove, search, and filter tasks. Use appropriate collections for different operations: ArrayList for all tasks, TreeSet for sorted display, and HashMap for quick lookup by ID.
Requirements:
Bonus Challenge
Add a deadline field (LocalDate) and a method getOverdueTasks() that returns tasks past their deadline with status not DONE. Add persistence by saving/loading tasks to a file.