Table of Contents
- Introduction
- TreeSet vs Other Sets
- Constructors and Creation
- Natural Ordering
- Custom Comparators
- Basic Operations
- Navigation Methods
- Range Operations
- Performance Characteristics
- Use Cases
- Best Practices
- Complete Examples
Introduction
TreeSet is a NavigableSet implementation based on a TreeMap. It stores elements in a sorted order and provides guaranteed log(n) time cost for basic operations.
Key Characteristics:
- Sorted Order: Elements are stored in sorted order
- No Duplicates: Like all Set implementations
- Red-Black Tree: Backed by a balanced tree structure
- Null Elements: Doesn't allow null elements (if natural ordering)
- Performance: O(log n) for add, remove, contains operations
TreeSet vs Other Sets
Comparison Table:
| Feature | TreeSet | HashSet | LinkedHashSet |
|---|---|---|---|
| Ordering | Sorted (natural/comparator) | No order | Insertion order |
| Implementation | Red-Black Tree | Hash table | Hash table + Linked list |
| Performance | O(log n) | O(1) | O(1) |
| Null elements | Not allowed (if natural) | Allowed | Allowed |
| Use Case | Sorted data | General purpose | Insertion order |
Code Comparison:
import java.util.*; public class SetComparison { public static void main(String[] args) { // TreeSet - Sorted order Set<String> treeSet = new TreeSet<>(); treeSet.add("Orange"); treeSet.add("Apple"); treeSet.add("Banana"); treeSet.add("Cherry"); System.out.println("TreeSet: " + treeSet); // Sorted order // HashSet - No order Set<String> hashSet = new HashSet<>(); hashSet.add("Orange"); hashSet.add("Apple"); hashSet.add("Banana"); hashSet.add("Cherry"); System.out.println("HashSet: " + hashSet); // Random order // LinkedHashSet - Insertion order Set<String> linkedHashSet = new LinkedHashSet<>(); linkedHashSet.add("Orange"); linkedHashSet.add("Apple"); linkedHashSet.add("Banana"); linkedHashSet.add("Cherry"); System.out.println("LinkedHashSet: " + linkedHashSet); // Insertion order } } Output:
TreeSet: [Apple, Banana, Cherry, Orange] # Sorted order HashSet: [Apple, Cherry, Banana, Orange] # Random order LinkedHashSet: [Orange, Apple, Banana, Cherry] # Insertion order
Constructors and Creation
Available Constructors:
import java.util.*; public class TreeSetConstructors { public static void main(String[] args) { // 1. Default constructor - natural ordering TreeSet<String> defaultSet = new TreeSet<>(); defaultSet.add("Banana"); defaultSet.add("Apple"); defaultSet.add("Cherry"); System.out.println("Default: " + defaultSet); // 2. Constructor with Comparator TreeSet<String> reverseSet = new TreeSet<>(Comparator.reverseOrder()); reverseSet.add("Banana"); reverseSet.add("Apple"); reverseSet.add("Cherry"); System.out.println("Reverse: " + reverseSet); // 3. Constructor from existing collection List<String> list = Arrays.asList("Orange", "Grape", "Mango"); TreeSet<String> fromCollection = new TreeSet<>(list); System.out.println("From collection: " + fromCollection); // 4. Constructor from sorted set TreeSet<String> fromSortedSet = new TreeSet<>(defaultSet); System.out.println("From sorted set: " + fromSortedSet); } } Output:
Default: [Apple, Banana, Cherry] Reverse: [Cherry, Banana, Apple] From collection: [Grape, Mango, Orange] From sorted set: [Apple, Banana, Cherry]
Natural Ordering
With Comparable Objects:
import java.util.*; class Student implements Comparable<Student> { private int id; private String name; private double gpa; public Student(int id, String name, double gpa) { this.id = id; this.name = name; this.gpa = gpa; } // Natural ordering by ID @Override public int compareTo(Student other) { return Integer.compare(this.id, other.id); } @Override public String toString() { return String.format("Student{id=%d, name='%s', gpa=%.2f}", id, name, gpa); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Student)) return false; Student student = (Student) o; return id == student.id; } @Override public int hashCode() { return Objects.hash(id); } } public class NaturalOrderingExample { public static void main(String[] args) { TreeSet<Student> students = new TreeSet<>(); students.add(new Student(103, "Alice", 3.8)); students.add(new Student(101, "Bob", 3.5)); students.add(new Student(102, "Charlie", 3.9)); students.add(new Student(100, "Diana", 3.7)); System.out.println("Students sorted by ID (natural order):"); for (Student student : students) { System.out.println(student); } } } Output:
Students sorted by ID (natural order): Student{id=100, name='Diana', gpa=3.70} Student{id=101, name='Bob', gpa=3.50} Student{id=102, name='Charlie', gpa=3.90} Student{id=103, name='Alice', gpa=3.80} Custom Comparators
Using Different Comparison Strategies:
import java.util.*; class Product { private String name; private double price; private int quantity; public Product(String name, double price, int quantity) { this.name = name; this.price = price; this.quantity = quantity; } public String getName() { return name; } public double getPrice() { return price; } public int getQuantity() { return quantity; } @Override public String toString() { return String.format("Product{name='%-10s', price=$%6.2f, quantity=%2d}", name, price, quantity); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Product)) return false; Product product = (Product) o; return Objects.equals(name, product.name); } @Override public int hashCode() { return Objects.hash(name); } } public class CustomComparatorExample { public static void main(String[] args) { // 1. Sort by name TreeSet<Product> byName = new TreeSet<>( Comparator.comparing(Product::getName) ); // 2. Sort by price TreeSet<Product> byPrice = new TreeSet<>( Comparator.comparingDouble(Product::getPrice) ); // 3. Sort by quantity (descending) TreeSet<Product> byQuantityDesc = new TreeSet<>( Comparator.comparingInt(Product::getQuantity).reversed() ); // 4. Sort by price then by name TreeSet<Product> byPriceThenName = new TreeSet<>( Comparator.comparingDouble(Product::getPrice) .thenComparing(Product::getName) ); // Add products List<Product> products = Arrays.asList( new Product("Laptop", 999.99, 5), new Product("Mouse", 25.99, 20), new Product("Keyboard", 75.50, 15), new Product("Monitor", 299.99, 8), new Product("Mouse", 19.99, 25) // Different mouse ); // Add to all sets for (Product product : products) { byName.add(product); byPrice.add(product); byQuantityDesc.add(product); byPriceThenName.add(product); } System.out.println("Sorted by Name:"); byName.forEach(System.out::println); System.out.println("\nSorted by Price:"); byPrice.forEach(System.out::println); System.out.println("\nSorted by Quantity (Descending):"); byQuantityDesc.forEach(System.out::println); System.out.println("\nSorted by Price then Name:"); byPriceThenName.forEach(System.out::println); } } Output:
Sorted by Name: Product{name='Keyboard ', price=$ 75.50, quantity=15} Product{name='Laptop ', price=$999.99, quantity= 5} Product{name='Monitor ', price=$299.99, quantity= 8} Product{name='Mouse ', price=$ 25.99, quantity=20} Sorted by Price: Product{name='Mouse ', price=$ 25.99, quantity=20} Product{name='Keyboard ', price=$ 75.50, quantity=15} Product{name='Monitor ', price=$299.99, quantity= 8} Product{name='Laptop ', price=$999.99, quantity= 5} Sorted by Quantity (Descending): Product{name='Mouse ', price=$ 25.99, quantity=20} Product{name='Keyboard ', price=$ 75.50, quantity=15} Product{name='Monitor ', price=$299.99, quantity= 8} Product{name='Laptop ', price=$999.99, quantity= 5} Sorted by Price then Name: Product{name='Mouse ', price=$ 25.99, quantity=20} Product{name='Keyboard ', price=$ 75.50, quantity=15} Product{name='Monitor ', price=$299.99, quantity= 8} Product{name='Laptop ', price=$999.99, quantity= 5} Basic Operations
Common Operations Examples:
import java.util.*; public class BasicOperations { public static void main(String[] args) { TreeSet<Integer> numbers = new TreeSet<>(); // Add elements numbers.add(50); numbers.add(20); numbers.add(80); numbers.add(10); numbers.add(30); numbers.add(70); numbers.add(40); numbers.add(60); System.out.println("TreeSet: " + numbers); System.out.println("Size: " + numbers.size()); System.out.println("Contains 30: " + numbers.contains(30)); System.out.println("Contains 35: " + numbers.contains(35)); // Remove elements numbers.remove(20); System.out.println("After removing 20: " + numbers); // First and last System.out.println("First element: " + numbers.first()); System.out.println("Last element: " + numbers.last()); // Iteration (sorted order) System.out.print("Iteration: "); for (Integer num : numbers) { System.out.print(num + " "); } System.out.println(); // Descending iteration System.out.print("Descending iteration: "); for (Integer num : numbers.descendingSet()) { System.out.print(num + " "); } System.out.println(); // Clear numbers.clear(); System.out.println("After clear - Empty: " + numbers.isEmpty()); System.out.println("Size: " + numbers.size()); } } Output:
TreeSet: [10, 20, 30, 40, 50, 60, 70, 80] Size: 8 Contains 30: true Contains 35: false After removing 20: [10, 30, 40, 50, 60, 70, 80] First element: 10 Last element: 80 Iteration: 10 30 40 50 60 70 80 Descending iteration: 80 70 60 50 40 30 10 After clear - Empty: true Size: 0
Navigation Methods
TreeSet Navigation Features:
import java.util.*; public class NavigationMethods { public static void main(String[] args) { TreeSet<Integer> numbers = new TreeSet<>(Arrays.asList( 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 )); System.out.println("Original set: " + numbers); // Lower and higher System.out.println("Lower than 45: " + numbers.lower(45)); // Greatest element < 45 System.out.println("Higher than 45: " + numbers.higher(45)); // Smallest element > 45 // Floor and ceiling System.out.println("Floor of 45: " + numbers.floor(45)); // Greatest element <= 45 System.out.println("Ceiling of 45: " + numbers.ceiling(45)); // Smallest element >= 45 // Head and tail sets System.out.println("Head set (elements < 50): " + numbers.headSet(50)); System.out.println("Head set inclusive (elements <= 50): " + numbers.headSet(50, true)); System.out.println("Tail set (elements >= 60): " + numbers.tailSet(60)); System.out.println("Tail set exclusive (elements > 60): " + numbers.tailSet(60, false)); // Subset System.out.println("Subset [40, 80): " + numbers.subSet(40, 80)); System.out.println("Subset [40, 80]: " + numbers.subSet(40, true, 80, true)); // Poll first and last System.out.println("Poll first: " + numbers.pollFirst() + ", Remaining: " + numbers); System.out.println("Poll last: " + numbers.pollLast() + ", Remaining: " + numbers); } } Output:
Original set: [10, 20, 30, 40, 50, 60, 70, 80, 90, 100] Lower than 45: 40 Higher than 45: 50 Floor of 45: 40 Ceiling of 45: 50 Head set (elements < 50): [10, 20, 30, 40] Head set inclusive (elements <= 50): [10, 20, 30, 40, 50] Tail set (elements >= 60): [60, 70, 80, 90, 100] Tail set exclusive (elements > 60): [70, 80, 90, 100] Subset [40, 80): [40, 50, 60, 70] Subset [40, 80]: [40, 50, 60, 70, 80] Poll first: 10, Remaining: [20, 30, 40, 50, 60, 70, 80, 90, 100] Poll last: 100, Remaining: [20, 30, 40, 50, 60, 70, 80, 90]
Range Operations
Practical Range Query Examples:
import java.util.*; public class RangeOperations { public static void main(String[] args) { TreeSet<Integer> scores = new TreeSet<>(Arrays.asList( 45, 67, 89, 92, 78, 56, 83, 71, 95, 62, 88, 76 )); System.out.println("All scores: " + scores); // Find scores in different ranges System.out.println("\n--- Grade Ranges ---"); System.out.println("Failing (< 60): " + scores.headSet(60)); System.out.println("Passing (60-69): " + scores.subSet(60, 70)); System.out.println("Good (70-79): " + scores.subSet(70, 80)); System.out.println("Very Good (80-89): " + scores.subSet(80, 90)); System.out.println("Excellent (>= 90): " + scores.tailSet(90)); // Find nearest scores int target = 75; System.out.println("\n--- Nearest to " + target + " ---"); System.out.println("Floor: " + scores.floor(target)); System.out.println("Ceiling: " + scores.ceiling(target)); System.out.println("Lower: " + scores.lower(target)); System.out.println("Higher: " + scores.higher(target)); // Range for scholarship (top 30%) int minScholarshipScore = getPercentile(scores, 70); System.out.println("\nScholarship candidates (top 30%): " + scores.tailSet(minScholarshipScore)); } private static int getPercentile(TreeSet<Integer> set, int percentile) { if (set.isEmpty()) return 0; int index = (int) Math.ceil(set.size() * percentile / 100.0) - 1; return set.stream().sorted().skip(index).findFirst().orElse(0); } } Output:
All scores: [45, 56, 62, 67, 71, 76, 78, 83, 88, 89, 92, 95] --- Grade Ranges --- Failing (< 60): [45, 56] Passing (60-69): [62, 67] Good (70-79): [71, 76, 78] Very Good (80-89): [83, 88, 89] Excellent (>= 90): [92, 95] --- Nearest to 75 --- Floor: 71 Ceiling: 76 Lower: 71 Higher: 76 Scholarship candidates (top 30%): [83, 88, 89, 92, 95]
Performance Characteristics
Time Complexity:
| Operation | Time Complexity |
|---|---|
| add() | O(log n) |
| remove() | O(log n) |
| contains() | O(log n) |
| first() / last() | O(1) |
| lower() / higher() | O(log n) |
| headSet() / tailSet() | O(log n) |
Performance Comparison:
import java.util.*; public class PerformanceComparison { public static void main(String[] args) { final int SIZE = 100000; // TreeSet TreeSet<Integer> treeSet = new TreeSet<>(); long startTime = System.nanoTime(); for (int i = 0; i < SIZE; i++) { treeSet.add(i); } long treeSetAddTime = System.nanoTime() - startTime; startTime = System.nanoTime(); treeSet.contains(SIZE / 2); long treeSetContainsTime = System.nanoTime() - startTime; // HashSet HashSet<Integer> hashSet = new HashSet<>(); startTime = System.nanoTime(); for (int i = 0; i < SIZE; i++) { hashSet.add(i); } long hashSetAddTime = System.nanoTime() - startTime; startTime = System.nanoTime(); hashSet.contains(SIZE / 2); long hashSetContainsTime = System.nanoTime() - startTime; System.out.println("Performance Comparison (nanoseconds):"); System.out.printf("TreeSet - Add: %,d, Contains: %,d\n", treeSetAddTime, treeSetContainsTime); System.out.printf("HashSet - Add: %,d, Contains: %,d\n", hashSetAddTime, hashSetContainsTime); System.out.printf("TreeSet add is %.2fx slower than HashSet\n", (double) treeSetAddTime / hashSetAddTime); } } Use Cases
1. Sorted Leaderboard:
import java.util.*; class Player implements Comparable<Player> { private String name; private int score; public Player(String name, int score) { this.name = name; this.score = score; } // Higher scores first @Override public int compareTo(Player other) { return Integer.compare(other.score, this.score); // Descending } public String getName() { return name; } public int getScore() { return score; } @Override public String toString() { return String.format("%-10s: %d", name, score); } } public class Leaderboard { private TreeSet<Player> players; public Leaderboard() { players = new TreeSet<>(); } public void addPlayer(String name, int score) { players.add(new Player(name, score)); } public void displayTopPlayers(int count) { System.out.println("Top " + count + " Players:"); int rank = 1; for (Player player : players) { if (rank > count) break; System.out.println(rank + ". " + player); rank++; } } public void displayRank(String playerName) { int rank = 1; for (Player player : players) { if (player.getName().equals(playerName)) { System.out.println(playerName + " is ranked #" + rank); return; } rank++; } System.out.println(playerName + " not found in leaderboard"); } public static void main(String[] args) { Leaderboard leaderboard = new Leaderboard(); leaderboard.addPlayer("Alice", 1500); leaderboard.addPlayer("Bob", 1800); leaderboard.addPlayer("Charlie", 1200); leaderboard.addPlayer("Diana", 2000); leaderboard.addPlayer("Eve", 1600); leaderboard.addPlayer("Frank", 1900); leaderboard.displayTopPlayers(3); System.out.println(); leaderboard.displayRank("Alice"); leaderboard.displayRank("Diana"); } } Output:
Top 3 Players: 1. Diana : 2000 2. Frank : 1900 3. Bob : 1800 Alice is ranked #5 Diana is ranked #1
2. Event Scheduler:
import java.util.*; class Event implements Comparable<Event> { private String name; private Date timestamp; public Event(String name, Date timestamp) { this.name = name; this.timestamp = timestamp; } @Override public int compareTo(Event other) { return this.timestamp.compareTo(other.timestamp); } public String getName() { return name; } public Date getTimestamp() { return timestamp; } @Override public String toString() { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return String.format("Event{name='%s', time=%s}", name, sdf.format(timestamp)); } } public class EventScheduler { private TreeSet<Event> events; public EventScheduler() { events = new TreeSet<>(); } public void scheduleEvent(String name, Date time) { events.add(new Event(name, time)); System.out.println("Scheduled: " + name + " at " + time); } public Event getNextEvent() { return events.isEmpty() ? null : events.first(); } public Event getNextEventAfter(Date time) { Event next = events.higher(new Event("", time)); return next; } public Set<Event> getEventsBetween(Date start, Date end) { return events.subSet(new Event("", start), true, new Event("", end), true); } public void displayUpcomingEvents(int count) { System.out.println("\nUpcoming " + count + " events:"); int displayed = 0; for (Event event : events) { if (displayed >= count) break; System.out.println((displayed + 1) + ". " + event); displayed++; } } public static void main(String[] args) throws Exception { EventScheduler scheduler = new EventScheduler(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); // Schedule events scheduler.scheduleEvent("Meeting", sdf.parse("2024-01-15 10:00")); scheduler.scheduleEvent("Lunch", sdf.parse("2024-01-15 12:30")); scheduler.scheduleEvent("Conference", sdf.parse("2024-01-15 09:00")); scheduler.scheduleEvent("Training", sdf.parse("2024-01-15 14:00")); scheduler.displayUpcomingEvents(3); Date searchTime = sdf.parse("2024-01-15 11:00"); Event next = scheduler.getNextEventAfter(searchTime); System.out.println("\nNext event after " + sdf.format(searchTime) + ": " + next); } } Output:
Scheduled: Meeting at Mon Jan 15 10:00:00 IST 2024 Scheduled: Lunch at Mon Jan 15 12:30:00 IST 2024 Scheduled: Conference at Mon Jan 15 09:00:00 IST 2024 Scheduled: Training at Mon Jan 15 14:00:00 IST 2024 Upcoming 3 events: 1. Event{name='Conference', time=2024-01-15 09:00:00} 2. Event{name='Meeting', time=2024-01-15 10:00:00} 3. Event{name='Lunch', time=2024-01-15 12:30:00} Next event after 2024-01-15 11:00: Lunch Best Practices
1. Consistent equals() and compareTo():
class ConsistentStudent implements Comparable<ConsistentStudent> { private int id; private String name; public ConsistentStudent(int id, String name) { this.id = id; this.name = name; } // compareTo consistent with equals @Override public int compareTo(ConsistentStudent other) { return Integer.compare(this.id, other.id); } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof ConsistentStudent)) return false; ConsistentStudent that = (ConsistentStudent) o; return id == that.id; } @Override public int hashCode() { return Objects.hash(id); } } 2. Handle Null Values:
public class NullHandling { public static void main(String[] args) { // TreeSet with natural ordering doesn't allow null try { TreeSet<String> naturalSet = new TreeSet<>(); naturalSet.add(null); // Throws NullPointerException } catch (NullPointerException e) { System.out.println("Natural ordering TreeSet doesn't allow null"); } // TreeSet with custom comparator can allow null TreeSet<String> customSet = new TreeSet<>( Comparator.nullsFirst(Comparator.naturalOrder()) ); customSet.add(null); customSet.add("Apple"); customSet.add("Banana"); System.out.println("With nullsFirst: " + customSet); } } 3. Choose Appropriate Initial Capacity:
public class TreeSetConfiguration { public static void main(String[] args) { // For large datasets, consider initial capacity // (Though TreeSet doesn't have capacity constructor like HashSet) // Better approach: Use appropriate comparator TreeSet<Integer> largeSet = new TreeSet<>(Comparator.reverseOrder()); // Add bulk data efficiently List<Integer> bulkData = Arrays.asList(5, 2, 8, 1, 9, 3, 7, 4, 6); largeSet.addAll(bulkData); System.out.println("Large set: " + largeSet); } } Complete Examples
Complete Working Example:
import java.util.*; import java.text.SimpleDateFormat; public class TreeSetCompleteExample { public static void main(String[] args) throws Exception { System.out.println("=== TreeSet Complete Example ===\n"); // Example 1: Basic Sorted Operations basicSortedOperations(); // Example 2: Custom Object Sorting customObjectSorting(); // Example 3: Navigation and Range Queries navigationAndRangeQueries(); // Example 4: Real-world Use Case - Product Catalog productCatalogExample(); } public static void basicSortedOperations() { System.out.println("1. Basic Sorted Operations:"); TreeSet<String> fruits = new TreeSet<>(); // Add in random order fruits.add("Orange"); fruits.add("Apple"); fruits.add("Banana"); fruits.add("Cherry"); fruits.add("Mango"); fruits.add("Grape"); System.out.println("Natural order: " + fruits); System.out.println("Reverse order: " + fruits.descendingSet()); System.out.println("First fruit: " + fruits.first()); System.out.println("Last fruit: " + fruits.last()); System.out.println(); } public static void customObjectSorting() { System.out.println("2. Custom Object Sorting:"); // Sort by name TreeSet<Employee> byName = new TreeSet<>( Comparator.comparing(Employee::getName) ); // Sort by salary (descending) TreeSet<Employee> bySalary = new TreeSet<>( Comparator.comparingDouble(Employee::getSalary).reversed() ); // Add employees byName.add(new Employee("John", 50000, "IT")); byName.add(new Employee("Alice", 60000, "HR")); byName.add(new Employee("Bob", 55000, "Finance")); byName.add(new Employee("Diana", 75000, "IT")); bySalary.addAll(byName); System.out.println("Sorted by Name:"); byName.forEach(System.out::println); System.out.println("\nSorted by Salary (Descending):"); bySalary.forEach(System.out::println); System.out.println(); } public static void navigationAndRangeQueries() { System.out.println("3. Navigation and Range Queries:"); TreeSet<Integer> numbers = new TreeSet<>(Arrays.asList( 10, 25, 35, 40, 50, 65, 70, 85, 90, 100 )); System.out.println("All numbers: " + numbers); int target = 45; System.out.println("\nNavigation around " + target + ":"); System.out.println("Floor: " + numbers.floor(target)); System.out.println("Ceiling: " + numbers.ceiling(target)); System.out.println("Lower: " + numbers.lower(target)); System.out.println("Higher: " + numbers.higher(target)); System.out.println("\nRange queries:"); System.out.println("Numbers < 50: " + numbers.headSet(50)); System.out.println("Numbers >= 70: " + numbers.tailSet(70)); System.out.println("Numbers between 30 and 80: " + numbers.subSet(30, 80)); System.out.println(); } public static void productCatalogExample() throws Exception { System.out.println("4. Product Catalog Example:"); ProductCatalog catalog = new ProductCatalog(); // Add products catalog.addProduct(new CatalogProduct("Laptop", 999.99, "Electronics")); catalog.addProduct(new CatalogProduct("Mouse", 25.99, "Electronics")); catalog.addProduct(new CatalogProduct("Desk", 199.99, "Furniture")); catalog.addProduct(new CatalogProduct("Chair", 149.99, "Furniture")); catalog.addProduct(new CatalogProduct("Monitor", 299.99, "Electronics")); System.out.println("All products by name:"); catalog.displayAllProducts(); System.out.println("\nProducts under $200:"); catalog.displayProductsUnderPrice(200); System.out.println("\nProducts in price range $100-$300:"); catalog.displayProductsInPriceRange(100, 300); System.out.println("\nElectronics products:"); catalog.displayProductsByCategory("Electronics"); } } // Supporting classes class Employee { private String name; private double salary; private String department; public Employee(String name, double salary, String department) { this.name = name; this.salary = salary; this.department = department; } public String getName() { return name; } public double getSalary() { return salary; } public String getDepartment() { return department; } @Override public String toString() { return String.format("Employee{name='%-6s', salary=$%6.2f, department='%s'}", name, salary, department); } } class CatalogProduct implements Comparable<CatalogProduct> { private String name; private double price; private String category; public CatalogProduct(String name, double price, String category) { this.name = name; this.price = price; this.category = category; } @Override public int compareTo(CatalogProduct other) { return this.name.compareTo(other.name); } public String getName() { return name; } public double getPrice() { return price; } public String getCategory() { return category; } @Override public String toString() { return String.format("Product{name='%-10s', price=$%6.2f, category='%s'}", name, price, category); } } class ProductCatalog { private TreeSet<CatalogProduct> productsByName; private TreeSet<CatalogProduct> productsByPrice; public ProductCatalog() { productsByName = new TreeSet<>(); productsByPrice = new TreeSet<>( Comparator.comparingDouble(CatalogProduct::getPrice) ); } public void addProduct(CatalogProduct product) { productsByName.add(product); productsByPrice.add(product); } public void displayAllProducts() { productsByName.forEach(System.out::println); } public void displayProductsUnderPrice(double maxPrice) { CatalogProduct dummy = new CatalogProduct("", maxPrice, ""); productsByPrice.headSet(dummy, true).forEach(System.out::println); } public void displayProductsInPriceRange(double minPrice, double maxPrice) { CatalogProduct minDummy = new CatalogProduct("", minPrice, ""); CatalogProduct maxDummy = new CatalogProduct("", maxPrice, ""); productsByPrice.subSet(minDummy, true, maxDummy, true) .forEach(System.out::println); } public void displayProductsByCategory(String category) { productsByName.stream() .filter(p -> p.getCategory().equals(category)) .forEach(System.out::println); } } Expected Output:
=== TreeSet Complete Example === 1. Basic Sorted Operations: Natural order: [Apple, Banana, Cherry, Grape, Mango, Orange] Reverse order: [Orange, Mango, Grape, Cherry, Banana, Apple] First fruit: Apple Last fruit: Orange 2. Custom Object Sorting: Sorted by Name: Employee{name='Alice ', salary=$60000.00, department='HR'} Employee{name='Bob ', salary=$55000.00, department='Finance'} Employee{name='Diana ', salary=$75000.00, department='IT'} Employee{name='John ', salary=$50000.00, department='IT'} Sorted by Salary (Descending): Employee{name='Diana ', salary=$75000.00, department='IT'} Employee{name='Alice ', salary=$60000.00, department='HR'} Employee{name='Bob ', salary=$55000.00, department='Finance'} Employee{name='John ', salary=$50000.00, department='IT'} 3. Navigation and Range Queries: All numbers: [10, 25, 35, 40, 50, 65, 70, 85, 90, 100] Navigation around 45: Floor: 40 Ceiling: 50 Lower: 40 Higher: 50 Range queries: Numbers < 50: [10, 25, 35, 40] Numbers >= 70: [70, 85, 90, 100] Numbers between 30 and 80: [35, 40, 50, 65, 70] 4. Product Catalog Example: All products by name: Product{name='Chair ', price=$149.99, category='Furniture'} Product{name='Desk ', price=$199.99, category='Furniture'} Product{name='Laptop ', price=$999.99, category='Electronics'} Product{name='Monitor ', price=$299.99, category='Electronics'} Product{name='Mouse ', price=$ 25.99, category='Electronics'} Products under $200: Product{name='Mouse ', price=$ 25.99, category='Electronics'} Product{name='Chair ', price=$149.99, category='Furniture'} Product{name='Desk ', price=$199.99, category='Furniture'} Products in price range $100-$300: Product{name='Chair ', price=$149.99, category='Furniture'} Product{name='Desk ', price=$199.99, category='Furniture'} Product{name='Monitor ', price=$299.99, category='Electronics'} Electronics products: Product{name='Laptop ', price=$999.99, category='Electronics'} Product{name='Monitor ', price=$299.99, category='Electronics'} Product{name='Mouse ', price=$ 25.99, category='Electronics'} Key Takeaways
- TreeSet maintains sorted order - elements are always sorted
- No duplicates - standard Set behavior
- Red-Black Tree implementation - provides O(log n) performance
- Natural ordering or custom comparator - flexible sorting
- Rich navigation API - ceiling, floor, higher, lower methods
- Range operations - headSet, tailSet, subSet for efficient queries
- No null elements - with natural ordering (unless specified in comparator)
- Perfect for sorted data - leaderboards, event schedulers, sorted catalogs
TreeSet is the ideal choice when you need a sorted collection with efficient range queries and navigation operations, making it perfect for applications that require maintaining data in sorted order.