Set in Java
Learn about collections that store unique elements only
💡 Think of a Set like a collection of unique stickers - you can't have two of the exact same sticker! If you try to add a sticker you already have, nothing happens. It's perfect for when you want to make sure there are no duplicates!
🎯 What is a Set?
A Set is a collection that contains no duplicate elements. Each element can appear at most once. Sets model the mathematical set abstraction and are perfect for membership testing, removing duplicates, and set operations.
import java.util.HashSet;import java.util.Set;public class BasicHashSet { public static void main(String[] args) { // Creating a HashSet Set<String> colors = new HashSet<>(); // Adding elements colors.add("Red"); // true - added successfully colors.add("Blue"); // true - added successfully colors.add("Green"); // true - added successfully colors.add("Red"); // false - duplicate! Not added System.out.println("Colors: " + colors); // Only 3 elements! System.out.println("Size: " + colors.size()); // 3 // Checking if element exists System.out.println("Has Blue? " + colors.contains("Blue")); // true System.out.println("Has Yellow? " + colors.contains("Yellow")); // false // Removing elements colors.remove("Blue"); System.out.println("After removing Blue: " + colors); // Iterating through set System.out.println("\nAll colors:"); for (String color : colors) { System.out.println("- " + color); } // Clear all elements colors.clear(); System.out.println("After clear, empty? " + colors.isEmpty()); // true }}🔍 📦 Types of Sets
Java provides different Set implementations with different characteristics:
HashSet
Fastest performance, uses hashing, no guaranteed order
LinkedHashSet
Maintains insertion order, slightly slower than HashSet
TreeSet
Elements sorted in natural order or by comparator, slowest
EnumSet
Specialized set for enum types, extremely fast and compact
import java.util.*;public class ComparingSetTypes { public static void main(String[] args) { // Same elements added to different sets String[] elements = {"Banana", "Apple", "Orange", "Apple", "Grape"}; // 1. HashSet - Fast, no order Set<String> hashSet = new HashSet<>(); for (String fruit : elements) { hashSet.add(fruit); } System.out.println("HashSet (random order): " + hashSet); // Example output: [Grape, Apple, Orange, Banana] // 2. LinkedHashSet - Maintains insertion order Set<String> linkedHashSet = new LinkedHashSet<>(); for (String fruit : elements) { linkedHashSet.add(fruit); } System.out.println("LinkedHashSet (insertion order): " + linkedHashSet); // Output: [Banana, Apple, Orange, Grape] // 3. TreeSet - Sorted order Set<String> treeSet = new TreeSet<>(); for (String fruit : elements) { treeSet.add(fruit); } System.out.println("TreeSet (sorted order): " + treeSet); // Output: [Apple, Banana, Grape, Orange] System.out.println("\nAll sets have same size: " + hashSet.size()); // All have 4 elements (duplicate "Apple" removed) }}🧹 Real-World Example: Removing Duplicates
import java.util.*;public class RemoveDuplicates { public static void main(String[] args) { // List with many duplicates List<Integer> numbersWithDuplicates = Arrays.asList( 1, 2, 3, 2, 4, 1, 5, 3, 6, 4, 7, 5, 8, 1, 9, 2 ); System.out.println("Original list: " + numbersWithDuplicates); System.out.println("Size: " + numbersWithDuplicates.size()); // Method 1: Using HashSet (fastest, no order) Set<Integer> uniqueNumbers = new HashSet<>(numbersWithDuplicates); System.out.println("\nUnique numbers (HashSet): " + uniqueNumbers); System.out.println("Size: " + uniqueNumbers.size()); // Method 2: Using LinkedHashSet (keeps insertion order) Set<Integer> uniqueOrdered = new LinkedHashSet<>(numbersWithDuplicates); System.out.println("\nUnique numbers (ordered): " + uniqueOrdered); // Method 3: Using TreeSet (sorted) Set<Integer> uniqueSorted = new TreeSet<>(numbersWithDuplicates); System.out.println("\nUnique numbers (sorted): " + uniqueSorted); // Converting back to list if needed List<Integer> uniqueList = new ArrayList<>(uniqueSorted); System.out.println("\nBack to list: " + uniqueList); } // Utility method to remove duplicates public static <T> List<T> removeDuplicates(List<T> list) { return new ArrayList<>(new LinkedHashSet<>(list)); }}🌳 TreeSet: Automatic Sorting
import java.util.*;public class TreeSetSorting { public static void main(String[] args) { // TreeSet automatically sorts elements TreeSet<Integer> scores = new TreeSet<>(); // Add scores in random order scores.add(85); scores.add(92); scores.add(78); scores.add(95); scores.add(88); scores.add(78); // Duplicate - won't be added System.out.println("Scores (auto-sorted): " + scores); // Output: [78, 85, 88, 92, 95] // TreeSet specific methods System.out.println("\nLowest score: " + scores.first()); // 78 System.out.println("Highest score: " + scores.last()); // 95 // Navigation methods System.out.println("Score lower than 90: " + scores.lower(90)); // 88 System.out.println("Score higher than 85: " + scores.higher(85)); // 88 System.out.println("Ceiling of 86: " + scores.ceiling(86)); // 88 (>= 86) System.out.println("Floor of 86: " + scores.floor(86)); // 85 (<= 86) // Subset operations System.out.println("\nScores from 80 to 90: " + scores.subSet(80, 90)); System.out.println("Scores above 90: " + scores.tailSet(90)); System.out.println("Scores below 90: " + scores.headSet(90)); // Descending order System.out.println("\nDescending order: " + scores.descendingSet()); // Custom sorting with Comparator TreeSet<String> names = new TreeSet<>(Collections.reverseOrder()); names.addAll(Arrays.asList("Alice", "David", "Bob", "Charlie")); System.out.println("\nNames (reverse order): " + names); // Output: [David, Charlie, Bob, Alice] }}👥 Real-World Example: Unique Visitors Tracker
import java.util.*;public class UniqueVisitors { private Set<String> visitors; private Map<String, Integer> visitCounts; public UniqueVisitors() { this.visitors = new HashSet<>(); this.visitCounts = new HashMap<>(); } // Record a visit public void recordVisit(String username) { visitors.add(username); // Add to unique visitors // Count total visits visitCounts.put(username, visitCounts.getOrDefault(username, 0) + 1); System.out.println(username + " visited. Total visits: " + visitCounts.get(username)); } // Get unique visitor count public int getUniqueVisitorCount() { return visitors.size(); } // Get total visit count public int getTotalVisitCount() { return visitCounts.values().stream().mapToInt(Integer::intValue).sum(); } // Check if user has visited public boolean hasVisited(String username) { return visitors.contains(username); } // Get all unique visitors public Set<String> getAllVisitors() { return new TreeSet<>(visitors); // Return sorted } // Print statistics public void printStats() { System.out.println("\n=== Visitor Statistics ==="); System.out.println("Unique visitors: " + getUniqueVisitorCount()); System.out.println("Total visits: " + getTotalVisitCount()); System.out.println("\nVisit counts:"); // Sort by visit count visitCounts.entrySet().stream() .sorted((e1, e2) -> e2.getValue().compareTo(e1.getValue())) .forEach(e -> System.out.println(" " + e.getKey() + ": " + e.getValue() + " visits")); } public static void main(String[] args) { UniqueVisitors tracker = new UniqueVisitors(); // Simulate website visits tracker.recordVisit("alice"); tracker.recordVisit("bob"); tracker.recordVisit("alice"); // Repeat visitor tracker.recordVisit("charlie"); tracker.recordVisit("bob"); // Repeat visitor tracker.recordVisit("alice"); // Repeat visitor tracker.recordVisit("david"); tracker.printStats(); // Check specific user System.out.println("\nHas 'eve' visited? " + tracker.hasVisited("eve")); System.out.println("Has 'alice' visited? " + tracker.hasVisited("alice")); }}🔄 Set Operations: Union, Intersection, Difference
import java.util.*;public class SetOperations { public static void main(String[] args) { Set<String> teamA = new HashSet<>(Arrays.asList("Alice", "Bob", "Charlie", "David")); Set<String> teamB = new HashSet<>(Arrays.asList("Charlie", "David", "Eve", "Frank")); System.out.println("Team A: " + teamA); System.out.println("Team B: " + teamB); // 1. UNION - All unique members from both teams Set<String> union = new HashSet<>(teamA); union.addAll(teamB); System.out.println("\nUnion (all members): " + union); // [Alice, Bob, Charlie, David, Eve, Frank] // 2. INTERSECTION - Members in both teams Set<String> intersection = new HashSet<>(teamA); intersection.retainAll(teamB); System.out.println("Intersection (in both): " + intersection); // [Charlie, David] // 3. DIFFERENCE - Members only in Team A Set<String> difference = new HashSet<>(teamA); difference.removeAll(teamB); System.out.println("Difference (only in A): " + difference); // [Alice, Bob] // 4. SYMMETRIC DIFFERENCE - Members in one team but not both Set<String> symmetricDiff = new HashSet<>(union); symmetricDiff.removeAll(intersection); System.out.println("Symmetric Difference: " + symmetricDiff); // [Alice, Bob, Eve, Frank] // 5. SUBSET - Is Team A subset of Union? boolean isSubset = union.containsAll(teamA); System.out.println("\nIs Team A subset of Union? " + isSubset); // true // 6. DISJOINT - Do sets have no common elements? Set<String> teamC = new HashSet<>(Arrays.asList("George", "Helen")); boolean areDisjoint = Collections.disjoint(teamA, teamC); System.out.println("Are Team A and C disjoint? " + areDisjoint); // true }}🔑 Key Concepts
No Duplicates
Each element must be unique based on equals() method
Adding 'Apple' twice only stores it once
No Ordering Guarantee (HashSet)
Elements may not maintain insertion order
Add [A, B, C] might give you [C, A, B]
Sorted Order (TreeSet)
Elements automatically sorted
Add [3, 1, 2] gives you [1, 2, 3]
Fast Lookup
Checking if element exists is very fast O(1) for HashSet
set.contains('Apple') is lightning fast
✨ Best Practices
- ✓Use HashSet for best performance when order doesn't matter
- ✓Use LinkedHashSet when you need predictable iteration order
- ✓Use TreeSet when you need sorted elements
- ✓Objects stored in Set must properly implement equals() and hashCode()
- ✓Use Set for removing duplicates from collections
- ✓Prefer Set interface type over implementation in declarations
- ✓Consider immutable sets with Set.of() for fixed collections
💼 Interview Tips
- •HashSet uses HashMap internally with dummy values
- •TreeSet is implemented using Red-Black tree (balanced BST)
- •HashSet is O(1) for add/remove/contains, TreeSet is O(log n)
- •Elements in HashSet must have good hashCode() implementation
- •TreeSet elements must be comparable (implement Comparable or use Comparator)
- •Remember that null is allowed in HashSet (one null) but not in TreeSet
- •Know the difference between Set operations: union, intersection, difference
- •Understand that Set.equals() compares elements, not order