Java Collections Framework
Java Programming (4343203)
Lecture 17
Unit 4: Advanced Java - Data Structures
GTU Computer Engineering Semester 4
Learning Objectives
- Understand the Java Collections Framework hierarchy
- Master List interface implementations (ArrayList, LinkedList, Vector)
- Learn Set interface and implementations (HashSet, TreeSet)
- Implement Map interface (HashMap, TreeMap, LinkedHashMap)
- Use iterators and enhanced for loops effectively
- Apply Comparable and Comparator for custom sorting
Focus: Efficient data storage, manipulation, and retrieval using Java's built-in collection classes.
Java Collections Framework Overview
What is Collections Framework?
- Unified architecture for storing/manipulating groups of objects
- Provides interfaces, implementations, and algorithms
- Reduces programming effort and increases performance
- Enables interoperability among unrelated APIs
Key Benefits
- Consistency: Common interface across collections
- Performance: Optimized implementations
- Interoperability: Standard interfaces
- Maintainability: Well-tested, documented APIs
Collection Interface Hierarchy:
Collection<E>
├── List<E>
│ ├── ArrayList<E>
│ ├── LinkedList<E>
│ └── Vector<E>
├── Set<E>
│ ├── HashSet<E>
│ ├── LinkedHashSet<E>
│ └── TreeSet<E>
└── Queue<E>
├── PriorityQueue<E>
└── LinkedList<E>
Map<K,V> (separate hierarchy)
├── HashMap<K,V>
├── LinkedHashMap<K,V>
└── TreeMap<K,V>
Collection<E>
├── List<E>
│ ├── ArrayList<E>
│ ├── LinkedList<E>
│ └── Vector<E>
├── Set<E>
│ ├── HashSet<E>
│ ├── LinkedHashSet<E>
│ └── TreeSet<E>
└── Queue<E>
├── PriorityQueue<E>
└── LinkedList<E>
Map<K,V> (separate hierarchy)
├── HashMap<K,V>
├── LinkedHashMap<K,V>
└── TreeMap<K,V>
Core Collection Interfaces
| Interface | Description | Key Features | Common Implementations |
|---|---|---|---|
| Collection<E> | Root interface | Basic operations: add, remove, contains | N/A (abstract) |
| List<E> | Ordered collection with duplicates | Index-based access, positional operations | ArrayList, LinkedList, Vector |
| Set<E> | Collection with no duplicates | Mathematical set operations | HashSet, TreeSet, LinkedHashSet |
| Queue<E> | Collection for holding elements before processing | FIFO operations: offer, poll, peek | LinkedList, PriorityQueue |
| Map<K,V> | Key-value pair mapping | Unique keys, efficient lookups | HashMap, TreeMap, LinkedHashMap |
List Interface - ArrayList
ArrayList Characteristics
- Resizable array implementation
- Allows duplicates and null values
- Maintains insertion order
- Random access (O(1) for get/set)
- Not synchronized (not thread-safe)
Performance Characteristics
- Access: O(1)
- Insert/Delete at end: O(1) amortized
- Insert/Delete at middle: O(n)
- Search: O(n)
import java.util.*;
public class ArrayListDemo {
public static void main(String[] args) {
// Create ArrayList
List fruits = new ArrayList<>();
// Adding elements
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Cherry");
fruits.add(1, "Orange"); // Insert at index
System.out.println("Fruits: " + fruits);
// Accessing elements
System.out.println("First fruit: " + fruits.get(0));
System.out.println("Size: " + fruits.size());
// Modifying elements
fruits.set(2, "Mango");
System.out.println("After modification: " + fruits);
// Searching
boolean hasApple = fruits.contains("Apple");
int index = fruits.indexOf("Banana");
System.out.println("Has Apple: " + hasApple);
System.out.println("Banana index: " + index);
// Removing elements
fruits.remove("Orange");
fruits.remove(0); // Remove by index
System.out.println("After removal: " + fruits);
// Converting to array
String[] fruitArray = fruits.toArray(new String[0]);
System.out.println("Array: " + Arrays.toString(fruitArray));
}
}
LinkedList Implementation
import java.util.*;
public class LinkedListDemo {
public static void main(String[] args) {
// LinkedList as List and Deque
LinkedList numbers = new LinkedList<>();
// Adding elements
numbers.add(10);
numbers.add(20);
numbers.add(30);
numbers.addFirst(5); // Add to beginning
numbers.addLast(40); // Add to end
System.out.println("LinkedList: " + numbers);
// Accessing elements
System.out.println("First: " + numbers.getFirst());
System.out.println("Last: " + numbers.getLast());
System.out.println("Element at index 2: " + numbers.get(2));
// Queue operations
numbers.offer(50); // Add to tail (same as addLast)
int head = numbers.poll(); // Remove and return head
System.out.println("After poll: " + numbers + ", removed: " + head);
// Stack operations
numbers.push(1); // Add to front (same as addFirst)
int top = numbers.pop(); // Remove and return first
System.out.println("After pop: " + numbers + ", removed: " + top);
// Iteration
System.out.print("Forward iteration: ");
Iterator iterator = numbers.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
System.out.print("Reverse iteration: ");
Iterator descIterator = numbers.descendingIterator();
while (descIterator.hasNext()) {
System.out.print(descIterator.next() + " ");
}
System.out.println();
// Performance comparison method
compareListPerformance();
}
private static void compareListPerformance() {
final int SIZE = 100000;
System.out.println("\n=== Performance Comparison ===");
// ArrayList performance
long start = System.currentTimeMillis();
List arrayList = new ArrayList<>();
for (int i = 0; i < SIZE; i++) {
arrayList.add(i);
}
long arrayListTime = System.currentTimeMillis() - start;
// LinkedList performance
start = System.currentTimeMillis();
List linkedList = new LinkedList<>();
for (int i = 0; i < SIZE; i++) {
linkedList.add(i);
}
long linkedListTime = System.currentTimeMillis() - start;
System.out.printf("ArrayList add time: %d ms%n", arrayListTime);
System.out.printf("LinkedList add time: %d ms%n", linkedListTime);
// Random access performance
start = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
arrayList.get(SIZE / 2);
}
long arrayListAccess = System.currentTimeMillis() - start;
start = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
linkedList.get(SIZE / 2);
}
long linkedListAccess = System.currentTimeMillis() - start;
System.out.printf("ArrayList random access time: %d ms%n", arrayListAccess);
System.out.printf("LinkedList random access time: %d ms%n", linkedListAccess);
}
}
Set Interface - HashSet and TreeSet
HashSet Characteristics
- Hash table implementation
- No duplicates, allows one null
- No guaranteed order
- O(1) average time for basic operations
import java.util.*;
// HashSet Demo
Set hashSet = new HashSet<>();
hashSet.add("Java");
hashSet.add("Python");
hashSet.add("C++");
hashSet.add("Java"); // Duplicate ignored
System.out.println("HashSet: " + hashSet);
// Output order is unpredictable
// Common operations
boolean hasJava = hashSet.contains("Java");
int size = hashSet.size();
hashSet.remove("C++");
System.out.println("Contains Java: " + hasJava);
System.out.println("Size: " + size);
TreeSet Characteristics
- Red-Black tree implementation
- Sorted set (natural ordering or Comparator)
- No duplicates, no null values
- O(log n) time for basic operations
// TreeSet Demo
Set treeSet = new TreeSet<>();
treeSet.add(30);
treeSet.add(10);
treeSet.add(20);
treeSet.add(40);
System.out.println("TreeSet: " + treeSet);
// Output: [10, 20, 30, 40] (sorted)
// NavigableSet operations
TreeSet numbers = (TreeSet) treeSet;
System.out.println("First: " + numbers.first());
System.out.println("Last: " + numbers.last());
System.out.println("Higher than 25: " + numbers.higher(25));
System.out.println("Lower than 25: " + numbers.lower(25));
// Subset operations
SortedSet subset = numbers.subSet(15, 35);
System.out.println("Subset [15,35): " + subset);
Map Interface - HashMap
import java.util.*;
public class HashMapDemo {
public static void main(String[] args) {
// Create HashMap
Map studentGrades = new HashMap<>();
// Adding key-value pairs
studentGrades.put("Alice", 85);
studentGrades.put("Bob", 92);
studentGrades.put("Charlie", 78);
studentGrades.put("Diana", 96);
System.out.println("Student grades: " + studentGrades);
// Accessing values
int aliceGrade = studentGrades.get("Alice");
System.out.println("Alice's grade: " + aliceGrade);
// Check if key exists
boolean hasEve = studentGrades.containsKey("Eve");
boolean hasGrade90 = studentGrades.containsValue(90);
System.out.println("Has Eve: " + hasEve);
System.out.println("Has grade 90: " + hasGrade90);
// Updating values
studentGrades.put("Alice", 88); // Update Alice's grade
studentGrades.putIfAbsent("Eve", 82); // Add only if key doesn't exist
System.out.println("After updates: " + studentGrades);
// Iteration methods
System.out.println("\n=== Iteration Methods ===");
// 1. Iterate over keys
System.out.print("Students: ");
for (String student : studentGrades.keySet()) {
System.out.print(student + " ");
}
System.out.println();
// 2. Iterate over values
System.out.print("Grades: ");
for (Integer grade : studentGrades.values()) {
System.out.print(grade + " ");
}
System.out.println();
// 3. Iterate over entries
System.out.println("Student-Grade pairs:");
for (Map.Entry entry : studentGrades.entrySet()) {
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
// 4. Java 8 forEach with lambda
System.out.println("Using forEach with lambda:");
studentGrades.forEach((student, grade) ->
System.out.println(student + " scored " + grade)
);
// Advanced operations
demonstrateAdvancedMapOperations(studentGrades);
}
private static void demonstrateAdvancedMapOperations(Map grades) {
System.out.println("\n=== Advanced Map Operations ===");
// Compute operations (Java 8+)
grades.compute("Alice", (key, value) -> value + 2); // Add 2 to Alice's grade
System.out.println("After compute: " + grades.get("Alice"));
// Merge operation
grades.merge("Bob", 5, Integer::sum); // Add 5 to Bob's grade
System.out.println("After merge: " + grades.get("Bob"));
// Replace operations
grades.replace("Charlie", 78, 80); // Replace only if current value is 78
grades.replaceAll((student, grade) -> Math.max(grade, 80)); // Ensure minimum grade of 80
System.out.println("After replacements: " + grades);
// Remove operations
grades.remove("Diana", 96); // Remove only if key-value pair matches
System.out.println("After conditional remove: " + grades);
}
}
TreeMap and LinkedHashMap
TreeMap Example
import java.util.*;
// TreeMap - sorted by keys
TreeMap capitals = new TreeMap<>();
capitals.put("USA", "Washington DC");
capitals.put("India", "New Delhi");
capitals.put("China", "Beijing");
capitals.put("Brazil", "Brasília");
System.out.println("TreeMap (sorted by keys):");
capitals.forEach((country, capital) ->
System.out.println(country + " -> " + capital)
);
// NavigableMap operations
System.out.println("First entry: " + capitals.firstEntry());
System.out.println("Last key: " + capitals.lastKey());
System.out.println("Higher key than 'India': " +
capitals.higherKey("India"));
// Subset operations
SortedMap subset =
capitals.subMap("Brazil", "USA");
System.out.println("Subset [Brazil, USA): " + subset);
// Custom comparator
TreeMap wordLengths =
new TreeMap<>((a, b) -> Integer.compare(a.length(), b.length()));
wordLengths.put("elephant", 8);
wordLengths.put("cat", 3);
wordLengths.put("butterfly", 9);
System.out.println("Sorted by length: " + wordLengths);
LinkedHashMap Example
import java.util.*;
// LinkedHashMap - maintains insertion order
LinkedHashMap languages =
new LinkedHashMap<>();
languages.put("Java", "Object-oriented");
languages.put("Python", "Interpreted");
languages.put("C++", "Compiled");
languages.put("JavaScript", "Scripting");
System.out.println("LinkedHashMap (insertion order):");
languages.forEach((lang, type) ->
System.out.println(lang + " -> " + type)
);
// LRU Cache using LinkedHashMap
LinkedHashMap lruCache =
new LinkedHashMap(16, 0.75f, true) {
@Override
protected boolean removeEldestEntry(
Map.Entry eldest) {
return size() > 3; // Max 3 entries
}
};
// Test LRU behavior
lruCache.put("A", 1);
lruCache.put("B", 2);
lruCache.put("C", 3);
System.out.println("Initial: " + lruCache);
lruCache.get("A"); // Access A (moves to end)
lruCache.put("D", 4); // Should remove B
System.out.println("After access and insert: " + lruCache);
Iterators and Enhanced For Loop
import java.util.*;
public class IteratorDemo {
public static void main(String[] args) {
List colors = Arrays.asList("Red", "Green", "Blue", "Yellow", "Orange");
System.out.println("=== Different Iteration Methods ===");
// 1. Enhanced for loop (for-each)
System.out.print("Enhanced for loop: ");
for (String color : colors) {
System.out.print(color + " ");
}
System.out.println();
// 2. Iterator
System.out.print("Iterator: ");
Iterator iterator = colors.iterator();
while (iterator.hasNext()) {
String color = iterator.next();
System.out.print(color + " ");
}
System.out.println();
// 3. ListIterator (bidirectional)
System.out.print("ListIterator (reverse): ");
ListIterator listIterator = colors.listIterator(colors.size());
while (listIterator.hasPrevious()) {
String color = listIterator.previous();
System.out.print(color + " ");
}
System.out.println();
// 4. Traditional for loop with index
System.out.print("Traditional for loop: ");
for (int i = 0; i < colors.size(); i++) {
System.out.print(colors.get(i) + " ");
}
System.out.println();
// 5. Java 8 Streams
System.out.print("Stream forEach: ");
colors.stream().forEach(color -> System.out.print(color + " "));
System.out.println();
// Safe iteration with modification
demonstrateSafeIteration();
}
private static void demonstrateSafeIteration() {
System.out.println("\n=== Safe Iteration with Modification ===");
List numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
// UNSAFE: ConcurrentModificationException
try {
for (Integer num : numbers) {
if (num % 2 == 0) {
numbers.remove(num); // This will throw exception
}
}
} catch (ConcurrentModificationException e) {
System.out.println("ConcurrentModificationException caught!");
}
// SAFE: Using Iterator.remove()
numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
Iterator iter = numbers.iterator();
while (iter.hasNext()) {
Integer num = iter.next();
if (num % 2 == 0) {
iter.remove(); // Safe removal
}
}
System.out.println("After safe removal of even numbers: " + numbers);
// SAFE: Using removeIf (Java 8+)
numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
numbers.removeIf(num -> num % 2 == 0);
System.out.println("Using removeIf: " + numbers);
// ListIterator for bidirectional traversal and modification
numbers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
ListIterator listIter = numbers.listIterator();
while (listIter.hasNext()) {
Integer num = listIter.next();
if (num == 3) {
listIter.set(30); // Replace 3 with 30
listIter.add(35); // Add 35 after current element
}
}
System.out.println("After ListIterator modifications: " + numbers);
}
}
Sorting with Comparable and Comparator
import java.util.*;
// Student class implementing Comparable
class Student implements Comparable {
private String name;
private int age;
private double gpa;
public Student(String name, int age, double gpa) {
this.name = name;
this.age = age;
this.gpa = gpa;
}
// Natural ordering by name
@Override
public int compareTo(Student other) {
return this.name.compareTo(other.name);
}
@Override
public String toString() {
return String.format("%s(age=%d, gpa=%.2f)", name, age, gpa);
}
// Getters
public String getName() { return name; }
public int getAge() { return age; }
public double getGpa() { return gpa; }
}
public class SortingDemo {
public static void main(String[] args) {
List students = Arrays.asList(
new Student("Alice", 20, 3.8),
new Student("Bob", 19, 3.6),
new Student("Charlie", 21, 3.9),
new Student("Diana", 20, 3.7)
);
System.out.println("Original list: " + students);
// 1. Natural sorting using Comparable (by name)
Collections.sort(students);
System.out.println("Sorted by name: " + students);
// 2. Custom sorting using Comparator - by age
students.sort(Comparator.comparingInt(Student::getAge));
System.out.println("Sorted by age: " + students);
// 3. Sort by GPA (descending)
students.sort(Comparator.comparingDouble(Student::getGpa).reversed());
System.out.println("Sorted by GPA (descending): " + students);
// 4. Multiple criteria sorting
students.sort(Comparator.comparingInt(Student::getAge)
.thenComparing(Student::getName));
System.out.println("Sorted by age, then name: " + students);
// 5. Complex comparator with lambda
students.sort((s1, s2) -> {
int ageCompare = Integer.compare(s1.getAge(), s2.getAge());
if (ageCompare != 0) return ageCompare;
return Double.compare(s2.getGpa(), s1.getGpa()); // GPA descending
});
System.out.println("Sorted by age, then GPA desc: " + students);
// Demonstrate with TreeSet (sorted set)
demonstrateSortedSet();
// Demonstrate with TreeMap (sorted map)
demonstrateSortedMap();
}
}
Sorted Collections Demonstration
private static void demonstrateSortedSet() {
System.out.println("\n=== TreeSet with Custom Comparator ===");
// TreeSet with custom comparator (by GPA descending)
TreeSet studentsByGpa = new TreeSet<>(
Comparator.comparingDouble(Student::getGpa).reversed()
);
studentsByGpa.add(new Student("Alice", 20, 3.8));
studentsByGpa.add(new Student("Bob", 19, 3.6));
studentsByGpa.add(new Student("Charlie", 21, 3.9));
studentsByGpa.add(new Student("Diana", 20, 3.7));
System.out.println("Students by GPA (desc): " + studentsByGpa);
// NavigableSet operations
System.out.println("Highest GPA student: " + studentsByGpa.first());
System.out.println("Lowest GPA student: " + studentsByGpa.last());
Student threshold = new Student("", 0, 3.7);
SortedSet highPerformers = studentsByGpa.headSet(threshold);
System.out.println("Students with GPA > 3.7: " + highPerformers);
}
private static void demonstrateSortedMap() {
System.out.println("\n=== TreeMap with Custom Comparator ===");
// TreeMap sorted by key length, then alphabetically
TreeMap wordFreq = new TreeMap<>(
Comparator.comparingInt(String::length)
.thenComparing(String::compareTo)
);
wordFreq.put("apple", 5);
wordFreq.put("cat", 3);
wordFreq.put("elephant", 2);
wordFreq.put("dog", 4);
wordFreq.put("butterfly", 1);
System.out.println("Words by length, then alphabetically:");
wordFreq.forEach((word, freq) ->
System.out.printf("%-10s: %d%n", word, freq)
);
// NavigableMap operations
System.out.println("First entry: " + wordFreq.firstEntry());
System.out.println("Words longer than 'dog': " + wordFreq.tailMap("dog", false));
}
// Additional utility class for complex sorting
class StudentComparators {
// Static comparators for different sorting criteria
public static final Comparator BY_NAME =
Comparator.comparing(Student::getName);
public static final Comparator BY_AGE =
Comparator.comparingInt(Student::getAge);
public static final Comparator BY_GPA =
Comparator.comparingDouble(Student::getGpa);
// Composite comparators
public static final Comparator BY_AGE_THEN_NAME =
BY_AGE.thenComparing(BY_NAME);
public static final Comparator BY_GPA_DESC_THEN_NAME =
BY_GPA.reversed().thenComparing(BY_NAME);
// Custom comparator for grade classification
public static final Comparator BY_GRADE_CLASSIFICATION = (s1, s2) -> {
String grade1 = getGradeClassification(s1.getGpa());
String grade2 = getGradeClassification(s2.getGpa());
int gradeCompare = grade1.compareTo(grade2);
return gradeCompare != 0 ? gradeCompare : s1.getName().compareTo(s2.getName());
};
private static String getGradeClassification(double gpa) {
if (gpa >= 3.8) return "A";
else if (gpa >= 3.5) return "B";
else if (gpa >= 3.0) return "C";
else return "D";
}
}
GTU Previous Year Question (Summer 2022)
Q: Write a Java program to demonstrate the use of ArrayList, HashMap, and TreeSet. The program should perform operations like adding, removing, searching, and iterating through elements. Also compare the performance characteristics of these collections.
Solution:
import java.util.*;
public class CollectionsComparison {
private static final int DATA_SIZE = 50000;
public static void main(String[] args) {
System.out.println("=== Java Collections Framework Demonstration ===\n");
// Demonstrate ArrayList
demonstrateArrayList();
// Demonstrate HashMap
demonstrateHashMap();
// Demonstrate TreeSet
demonstrateTreeSet();
// Performance comparison
performanceComparison();
}
private static void demonstrateArrayList() {
System.out.println("--- ArrayList Demonstration ---");
ArrayList books = new ArrayList<>();
// Adding elements
books.add("Java: The Complete Reference");
books.add("Effective Java");
books.add("Clean Code");
books.add("Design Patterns");
books.add(1, "Head First Java"); // Insert at specific position
System.out.println("Books after adding: " + books);
System.out.println("Size: " + books.size());
// Accessing elements
System.out.println("First book: " + books.get(0));
System.out.println("Last book: " + books.get(books.size() - 1));
// Searching
boolean hasCleanCode = books.contains("Clean Code");
int index = books.indexOf("Effective Java");
System.out.println("Contains 'Clean Code': " + hasCleanCode);
System.out.println("Index of 'Effective Java': " + index);
// Modifying elements
books.set(2, "Spring in Action");
System.out.println("After modification: " + books);
// Iteration methods
System.out.print("Enhanced for loop: ");
for (String book : books) {
System.out.print("[" + book.substring(0, Math.min(book.length(), 10)) + "...] ");
}
System.out.println();
System.out.print("Iterator: ");
Iterator iter = books.iterator();
while (iter.hasNext()) {
String book = iter.next();
System.out.print("[" + book.substring(0, Math.min(book.length(), 10)) + "...] ");
}
System.out.println();
// Removing elements
books.remove("Design Patterns");
books.remove(0); // Remove by index
System.out.println("After removal: " + books);
// Bulk operations
List newBooks = Arrays.asList("Spring Boot", "Microservices", "Docker");
books.addAll(newBooks);
System.out.println("After adding all: " + books);
// Sorting
Collections.sort(books);
System.out.println("After sorting: " + books);
System.out.println();
}
}
HashMap Demonstration:
private static void demonstrateHashMap() {
System.out.println("--- HashMap Demonstration ---");
HashMap productPrices = new HashMap<>();
// Adding key-value pairs
productPrices.put("Laptop", 999.99);
productPrices.put("Smartphone", 699.99);
productPrices.put("Tablet", 399.99);
productPrices.put("Headphones", 199.99);
productPrices.put("Keyboard", 79.99);
System.out.println("Product prices: " + productPrices);
System.out.println("Size: " + productPrices.size());
// Accessing values
Double laptopPrice = productPrices.get("Laptop");
System.out.println("Laptop price: $" + laptopPrice);
// Checking existence
boolean hasSmartphone = productPrices.containsKey("Smartphone");
boolean hasPrice500 = productPrices.containsValue(500.0);
System.out.println("Has Smartphone: " + hasSmartphone);
System.out.println("Has price $500: " + hasPrice500);
// Updating values
productPrices.put("Laptop", 899.99); // Update existing
productPrices.putIfAbsent("Mouse", 29.99); // Add if not present
System.out.println("After updates: " + productPrices);
// Iteration methods
System.out.println("Iteration methods:");
// 1. Key set iteration
System.out.print("Keys: ");
for (String product : productPrices.keySet()) {
System.out.print(product + " ");
}
System.out.println();
// 2. Values iteration
System.out.print("Values: $");
for (Double price : productPrices.values()) {
System.out.print(price + " $");
}
System.out.println();
// 3. Entry set iteration
System.out.println("Product-Price pairs:");
for (Map.Entry entry : productPrices.entrySet()) {
System.out.printf(" %-12s: $%.2f%n", entry.getKey(), entry.getValue());
}
// 4. Java 8 forEach
System.out.println("Using forEach with lambda:");
productPrices.forEach((product, price) ->
System.out.printf(" %s costs $%.2f%n", product, price)
);
// Advanced operations (Java 8+)
productPrices.compute("Laptop", (key, value) -> value * 0.9); // 10% discount
productPrices.merge("Tablet", 50.0, Double::sum); // Add $50
System.out.println("After compute and merge: " + productPrices);
// Removing elements
productPrices.remove("Keyboard");
productPrices.remove("Mouse", 29.99); // Remove only if value matches
System.out.println("After removal: " + productPrices);
System.out.println();
}
TreeSet Demonstration:
private static void demonstrateTreeSet() {
System.out.println("--- TreeSet Demonstration ---");
TreeSet scores = new TreeSet<>();
// Adding elements (automatically sorted)
scores.add(85);
scores.add(92);
scores.add(78);
scores.add(96);
scores.add(82);
scores.add(92); // Duplicate - will be ignored
System.out.println("Scores (sorted): " + scores);
System.out.println("Size: " + scores.size());
// Basic operations
boolean hasScore90 = scores.contains(90);
System.out.println("Contains score 90: " + hasScore90);
// NavigableSet operations
System.out.println("First (lowest) score: " + scores.first());
System.out.println("Last (highest) score: " + scores.last());
System.out.println("Score higher than 85: " + scores.higher(85));
System.out.println("Score lower than 85: " + scores.lower(85));
System.out.println("Ceiling of 86: " + scores.ceiling(86));
System.out.println("Floor of 86: " + scores.floor(86));
// Subset operations
SortedSet passedScores = scores.tailSet(80); // >= 80
System.out.println("Passed scores (>= 80): " + passedScores);
SortedSet excellentScores = scores.headSet(95); // < 95
System.out.println("Excellent scores (< 95): " + excellentScores);
SortedSet goodScores = scores.subSet(80, 90); // [80, 90)
System.out.println("Good scores [80, 90): " + goodScores);
// Iteration
System.out.print("Forward iteration: ");
for (Integer score : scores) {
System.out.print(score + " ");
}
System.out.println();
System.out.print("Reverse iteration: ");
Iterator descIter = scores.descendingIterator();
while (descIter.hasNext()) {
System.out.print(descIter.next() + " ");
}
System.out.println();
// Removing elements
scores.pollFirst(); // Remove and return first
scores.pollLast(); // Remove and return last
scores.remove(85); // Remove specific element
System.out.println("After removals: " + scores);
// TreeSet with custom comparator
TreeSet words = new TreeSet<>(
Comparator.comparing(String::length)
.thenComparing(String::compareToIgnoreCase)
);
words.addAll(Arrays.asList("elephant", "cat", "butterfly", "dog", "ant"));
System.out.println("Words sorted by length then alphabetically: " + words);
System.out.println();
}
Performance Comparison:
private static void performanceComparison() {
System.out.println("--- Performance Comparison ---");
System.out.println("Testing with " + DATA_SIZE + " elements\n");
// Test data
List testData = new ArrayList<>();
for (int i = 0; i < DATA_SIZE; i++) {
testData.add((int) (Math.random() * DATA_SIZE));
}
// ArrayList performance
System.out.println("ArrayList Performance:");
testArrayListPerformance(testData);
// HashMap performance
System.out.println("\nHashMap Performance:");
testHashMapPerformance(testData);
// TreeSet performance
System.out.println("\nTreeSet Performance:");
testTreeSetPerformance(testData);
// Summary comparison
System.out.println("\n=== Performance Summary ===");
System.out.println("Operation | ArrayList | HashMap | TreeSet");
System.out.println("-------------|-----------|---------|--------");
System.out.println("Insert | O(1)* | O(1)* | O(log n)");
System.out.println("Search | O(n) | O(1)* | O(log n)");
System.out.println("Delete | O(n) | O(1)* | O(log n)");
System.out.println("Iteration | O(n) | O(n) | O(n)");
System.out.println("Memory | Low | Medium | Medium");
System.out.println("Duplicates | Allowed | Values | Not allowed");
System.out.println("Ordering | Insertion | None | Natural/Custom");
System.out.println("* Average case, worst case can be O(n)");
}
private static void testArrayListPerformance(List testData) {
ArrayList arrayList = new ArrayList<>();
// Insert performance
long start = System.currentTimeMillis();
for (Integer value : testData) {
arrayList.add(value);
}
long insertTime = System.currentTimeMillis() - start;
// Search performance
start = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
arrayList.contains(testData.get(i));
}
long searchTime = System.currentTimeMillis() - start;
// Random access performance
start = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
arrayList.get(i % arrayList.size());
}
long accessTime = System.currentTimeMillis() - start;
System.out.printf(" Insert: %d ms, Search: %d ms, Access: %d ms%n",
insertTime, searchTime, accessTime);
}
private static void testHashMapPerformance(List testData) {
HashMap hashMap = new HashMap<>();
// Insert performance
long start = System.currentTimeMillis();
for (int i = 0; i < testData.size(); i++) {
hashMap.put(testData.get(i), i);
}
long insertTime = System.currentTimeMillis() - start;
// Search performance
start = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
hashMap.containsKey(testData.get(i));
}
long searchTime = System.currentTimeMillis() - start;
System.out.printf(" Insert: %d ms, Search: %d ms%n", insertTime, searchTime);
}
private static void testTreeSetPerformance(List testData) {
TreeSet treeSet = new TreeSet<>();
// Insert performance
long start = System.currentTimeMillis();
for (Integer value : testData) {
treeSet.add(value);
}
long insertTime = System.currentTimeMillis() - start;
// Search performance
start = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
treeSet.contains(testData.get(i));
}
long searchTime = System.currentTimeMillis() - start;
System.out.printf(" Insert: %d ms, Search: %d ms, Size: %d (unique)%n",
insertTime, searchTime, treeSet.size());
}
}
Solution Features:
- Comprehensive demonstrations of ArrayList, HashMap, and TreeSet
- All major operations: add, remove, search, iterate
- Performance benchmarking and comparison
- Real-world examples with practical use cases
- Detailed performance characteristics analysis
🧪 Hands-on Lab Exercise
Lab 17: Student Management System
Task: Create a comprehensive student management system using various collection types to store and manipulate student data efficiently.
Requirements:
- Use
ArrayList<Student>to maintain student records - Use
HashMap<String, Student>for quick student lookup by ID - Use
TreeSet<Student>to maintain students sorted by GPA - Implement search, sort, and filter operations
- Create custom comparators for different sorting criteria
- Demonstrate iterator usage for safe collection modification
Challenge: Implement a course enrollment system using nested collections (Map<String, Set<Student>>) and ensure data consistency across all collections.
📚 Lecture Summary
Key Collections Covered
- List: ArrayList, LinkedList, Vector
- Set: HashSet, TreeSet, LinkedHashSet
- Map: HashMap, TreeMap, LinkedHashMap
- Queue: LinkedList, PriorityQueue
Important Concepts
- Collection interfaces and implementations
- Iterator patterns and safe iteration
- Comparable vs Comparator
- Performance characteristics
Best Practices
- Choose appropriate collection based on use case
- Use generics for type safety
- Prefer interface types for variable declarations
- Use enhanced for loops when possible
- Handle ConcurrentModificationException
- Consider performance implications
🎯 Next Lecture Preview
Lecture 18: Generics and Type Safety
- Generic classes and methods
- Bounded type parameters
- Wildcards and type erasure
- Generic collections and type safety

