TreeSet Mechanics
TreeSet is a Set implementation that maintains elements in a sorted order using a self-balancing binary tree (red-black tree). It does not allow duplicates and automatically arranges entries based on natural ordering or a custom comparator.
Basic Usage with Standard Types
import java.util.Set;
import java.util.TreeSet;
public class TreeSetBasics {
public static void main(String[] args) {
Set<Integer> numbers = new TreeSet<>();
numbers.add(45);
numbers.add(12);
numbers.add(30);
numbers.add(12); // Duplicate, ignored
numbers.add(99);
System.out.println(numbers); // [12, 30, 45, 99]
Set<String> words = new TreeSet<>();
words.add("banana");
words.add("apple");
words.add("cherry");
words.add("apple"); // Duplicate
System.out.println(words); // [apple, banana, cherry]
}
}
Storing Custom Objects
To store custom objects, they must define an ordering. The standard approach is implementing the Comparable interface.
import java.util.Set;
import java.util.TreeSet;
class Student implements Comparable<Student> {
String firstName;
int score;
public Student(String firstName, int score) {
this.firstName = firstName;
this.score = score;
}
@Override
public int compareTo(Student other) {
// Sort by score ascending
return this.score - other.score;
}
@Override
public String toString() {
return firstName + ":" + score;
}
}
public class CustomTreeSet {
public static void main(String[] args) {
Set<Student> roster = new TreeSet<>();
roster.add(new Student("Alice", 88));
roster.add(new Student("Bob", 75));
roster.add(new Student("Charlie", 88)); // Same score as Alice
System.out.println(roster); // [Bob:75, Alice:88]
}
}
Comparison Logic (compareTo):
- Negative: Current object is smaller (comes first).
- Zero: Objects are considered equal (duplicate removed).
- Positive: Current object is larger (comes after).
In the example above, Charlie is removed because his score matches Alice's, resulting in a 0 return.
Complex Sorting with Comparator
For scenarios requiring conditional sorting (e.g., sort by age, then by name), use a Comparator.
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
class Worker {
String name;
int age;
public Worker(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + "(" + age + ")";
}
}
public class ComparatorExample {
public static void main(String[] args) {
// Anonymous Comparator: Sort by age, then alphabetically by name
Set<Worker> staff = new TreeSet<>(new Comparator<Worker>() {
@Override
public int compare(Worker w1, Worker w2) {
if (w1.age != w2.age) {
return w1.age - w2.age;
}
return w1.name.compareTo(w2.name);
}
});
staff.add(new Worker("John", 30));
staff.add(new Worker("Jane", 25));
staff.add(new Worker("John", 25));
System.out.println(staff); // [John(25), Jane(25), John(30)]
}
}
Inner Classes
Member Inner Class
A class defined within another class. It has access to the outer class's members.
class Company {
String ceo = "Tim";
class Department {
String lead = "Alex";
public void display() {
System.out.println("CEO: " + ceo + ", Lead: " + lead);
}
}
}
public class InnerClassDemo {
public static void main(String[] args) {
Company.Department dept = new Company().new Department();
dept.display(); // CEO: Tim, Lead: Alex
}
}
Static Nested Class
A static class inside another class. It cannot access non-static members of the outer class directly.
class Outer {
static String tag = "STATIC";
static class Nested {
public void print() {
System.out.println(tag); // Accesses static member
}
}
}
public class StaticNestedDemo {
public static void main(String[] args) {
Outer.Nested nested = new Outer.Nested();
nested.print(); // STATIC
}
}
Anonymous Inner Class
Used to instantiate and define an interface or abstract class implementation on the fly, often for event listeners or comparators.
interface Logger {
void log(String msg);
}
public class AnonymousDemo {
public static void main(String[] args) {
Logger consoleLogger = new Logger() {
@Override
public void log(String msg) {
System.out.println("[CONSOLE] " + msg);
}
};
consoleLogger.log("System initialized");
}
}
Map Collections
The Map interface stores data in key-value pairs. Keys must be unique; values can be duplicated.
Common Methods:
put(K, V): Adds or updates a key-value pair.get(K): Retrieves the value associated with a key.keySet(): Returns aSetof all keys.values(): Returns aCollectionof all values.entrySet(): Returns aSetof key-value pair mappings.
HashMap Example
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapDemo {
public static void main(String[] args) {
Map<Integer, String> userMap = new HashMap<>();
// Add
userMap.put(101, "Mike");
userMap.put(102, "Sarah");
userMap.put(103, "Mike"); // Duplicate value allowed
// Retrieve
System.out.println(userMap.get(102)); // Sarah
// Check existence
System.out.println(userMap.containsKey(101)); // true
// Iterate over keys
Set<Integer> ids = userMap.keySet();
for (int id : ids) {
System.out.println("ID: " + id);
}
// Iterate over entries
for (Map.Entry<Integer, String> entry : userMap.entrySet()) {
System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
}
// Values
Collection<String> names = userMap.values();
System.out.println("Total users: " + names.size());
}
}