Day 16: Collections - Set and Map
Set is a collection that does not allow duplicates, and Map stores data as key-value pairs. A Set is like a bag of marbles where you keep only one of each color, while a Map is like a dictionary where you look up definitions (values) by words (keys).
HashSet and TreeSet
Two implementations for handling duplicate-free sets.
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;
public class SetExample {
public static void main(String[] args) {
// HashSet: no order guarantee, O(1) access
Set<String> hashSet = new HashSet<>();
hashSet.add("Java");
hashSet.add("Python");
hashSet.add("Go");
hashSet.add("Java"); // Duplicate! Not added
hashSet.add("Rust");
System.out.println("HashSet: " + hashSet); // Unordered
System.out.println("Size: " + hashSet.size()); // 4 (duplicates excluded)
System.out.println("Contains Java? " + hashSet.contains("Java")); // true
// LinkedHashSet: maintains insertion order
Set<String> linkedSet = new LinkedHashSet<>();
linkedSet.add("First");
linkedSet.add("Second");
linkedSet.add("Third");
System.out.println("LinkedHashSet: " + linkedSet); // Insertion order maintained
// TreeSet: auto-sorted (ascending)
Set<Integer> treeSet = new TreeSet<>();
treeSet.add(42);
treeSet.add(15);
treeSet.add(8);
treeSet.add(99);
treeSet.add(23);
System.out.println("TreeSet: " + treeSet); // [8, 15, 23, 42, 99]
// Set operations
Set<String> setA = new HashSet<>(Set.of("Java", "Python", "Go"));
Set<String> setB = new HashSet<>(Set.of("Python", "Rust", "Go"));
// Union
Set<String> union = new HashSet<>(setA);
union.addAll(setB);
System.out.println("Union: " + union);
// Intersection
Set<String> intersection = new HashSet<>(setA);
intersection.retainAll(setB);
System.out.println("Intersection: " + intersection);
// Difference
Set<String> difference = new HashSet<>(setA);
difference.removeAll(setB);
System.out.println("Difference: " + difference);
}
}
HashMap Basics
The most commonly used Map implementation that stores key-value pairs.
import java.util.HashMap;
import java.util.Map;
public class HashMapBasic {
public static void main(String[] args) {
Map<String, Integer> scores = new HashMap<>();
// Add entries
scores.put("Alice", 85);
scores.put("Bob", 92);
scores.put("Charlie", 78);
scores.put("Diana", 95);
// Retrieve
System.out.println("Alice's score: " + scores.get("Alice")); // 85
System.out.println("Missing key: " + scores.get("Eve")); // null
System.out.println("Default: " + scores.getOrDefault("Eve", 0)); // 0
// Update (put with same key overwrites the value)
scores.put("Alice", 90);
System.out.println("After update: " + scores.get("Alice")); // 90
// Contains check
System.out.println("Has key? " + scores.containsKey("Bob")); // true
System.out.println("Has value? " + scores.containsValue(78)); // true
// Remove
scores.remove("Charlie");
System.out.println("Size: " + scores.size()); // 3
// Iteration methods
// 1. entrySet (most efficient when both key and value are needed)
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
// 2. keySet
for (String name : scores.keySet()) {
System.out.println(name + " -> " + scores.get(name));
}
// 3. forEach + lambda
scores.forEach((name, score) ->
System.out.println(name + " = " + score));
}
}
Advanced Map Usage
Convenient methods added since Java 8.
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class MapAdvanced {
public static void main(String[] args) {
// Word frequency counting
String text = "Java is an object-oriented language Java is platform-independent Java is safe";
String[] words = text.split(" ");
Map<String, Integer> wordCount = new HashMap<>();
for (String word : words) {
// merge: merge if key exists, add if not
wordCount.merge(word, 1, Integer::sum);
}
System.out.println("Word frequency: " + wordCount);
// putIfAbsent: add only if key is absent
Map<String, String> config = new HashMap<>();
config.put("host", "localhost");
config.putIfAbsent("host", "remote-server"); // Already exists, ignored
config.putIfAbsent("port", "8080"); // Absent, so added
System.out.println("Config: " + config);
// computeIfAbsent: cache pattern
Map<Integer, String> cache = new HashMap<>();
String result = cache.computeIfAbsent(42, key -> {
System.out.println("Performing expensive computation...");
return "result-" + key;
});
System.out.println("First call: " + result);
// Second call: already cached, no computation
String cached = cache.computeIfAbsent(42, key -> "new computation");
System.out.println("Cache hit: " + cached);
// TreeMap: auto-sorted by key
Map<String, Integer> treeMap = new TreeMap<>();
treeMap.put("banana", 3);
treeMap.put("apple", 5);
treeMap.put("cherry", 1);
System.out.println("TreeMap: " + treeMap); // Alphabetical order
// Immutable Map creation
Map<String, Integer> immutable = Map.of(
"one", 1,
"two", 2,
"three", 3
);
System.out.println("Immutable Map: " + immutable);
}
}
Practical Example: Phone Book
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PhoneBook {
private final Map<String, List<String>> contacts = new HashMap<>();
void addContact(String name, String phone) {
contacts.computeIfAbsent(name, k -> new ArrayList<>()).add(phone);
System.out.println("Added " + phone + " for " + name);
}
List<String> findByName(String name) {
return contacts.getOrDefault(name, List.of());
}
void removeContact(String name) {
if (contacts.remove(name) != null) {
System.out.println(name + " removed");
} else {
System.out.println(name + " not found");
}
}
void printAll() {
System.out.println("=== Phone Book ===");
contacts.forEach((name, phones) -> {
System.out.println(name + ": " + String.join(", ", phones));
});
System.out.println("Total " + contacts.size() + " contacts");
}
Map<String, Integer> getStatistics() {
Map<String, Integer> stats = new HashMap<>();
stats.put("Total contacts", contacts.size());
stats.put("Total phone numbers", contacts.values().stream()
.mapToInt(List::size).sum());
return stats;
}
public static void main(String[] args) {
PhoneBook phoneBook = new PhoneBook();
phoneBook.addContact("Alice", "010-1234-5678");
phoneBook.addContact("Alice", "02-999-0000"); // Same name, different number
phoneBook.addContact("Bob", "010-9876-5432");
phoneBook.addContact("Charlie", "010-5555-3333");
phoneBook.printAll();
System.out.println("\nAlice's numbers: " + phoneBook.findByName("Alice"));
System.out.println("Statistics: " + phoneBook.getStatistics());
}
}
Today’s Exercises
-
Find Duplicate Characters: Classify characters in a string into duplicate and unique sets. Input:
"programming", Output: duplicates={g, r, m}, unique={p, o, a, i, n}. -
Student Grouping: Use
Map<String, List<Student>>to group students by grade. Print the list of A-grade students, B-grade students, etc. -
English Dictionary: Implement an English dictionary using
TreeMap. Create features for adding words, searching, retrieving a list of words starting with a specific letter (usingsubMap), and printing all words in alphabetical order.