0Pricing
Java Academy · Lesson

Custom Ordering in Tree Collections

Supply a Comparator to TreeMap/TreeSet to define domain-specific sort orders.

Custom Ordering in Tree Collections is a free Java Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Java Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Why Custom Ordering?

Tree collections (TreeMap, TreeSet) use natural ordering by default. When your domain objects don't have a natural order, or you need a different sort, you supply a Comparator at construction time.

Comparator at TreeMap Construction

Pass a comparator to sort keys by a custom rule — for example, reverse alphabetical order:

import java.util.*;

TreeMap<String, Integer> map = new TreeMap<>(Comparator.reverseOrder());
map.put("banana", 2);
map.put("apple", 1);
map.put("cherry", 3);

map.forEach((k,v) -> System.out.println(k)); // cherry, banana, apple

Comparator at TreeSet Construction

Supply a comparator to TreeSet to control sort order independently of the element's natural ordering:

TreeSet<String> byLength = new TreeSet<>(
    Comparator.comparingInt(String::length)
              .thenComparing(Comparator.naturalOrder())
);
byLength.addAll(List.of("fig","apple","kiwi","date","banana"));

for (String s : byLength) System.out.print(s + " ");
// fig date kiwi apple banana

Sorting Objects by Multiple Fields

Chain comparators to sort by a primary field, then a secondary field as a tiebreaker:

record Employee(String name, String dept, int salary) {}

TreeSet<Employee> sorted = new TreeSet<>(
    Comparator.comparing(Employee::dept)
              .thenComparingInt(Employee::salary).reversed()
              .thenComparing(Employee::name)
);
sorted.add(new Employee("Alice", "Eng", 90_000));
sorted.add(new Employee("Bob",   "Eng", 85_000));
sorted.add(new Employee("Carol", "HR",  70_000));

for (Employee e : sorted) System.out.println(e.dept()+" "+e.name());

Consistency with equals

Critical rule: the comparator used by TreeSet/TreeMap defines equality for the collection. If comparator.compare(a, b) == 0, both a and b are considered the same key — even if a.equals(b) is false.

// Comparator ignoring case — "apple" and "APPLE" become the same key!
TreeSet<String> ci = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
ci.add("apple");
ci.add("APPLE"); // not added — same by comparator
System.out.println(ci.size()); // 1

Case-Insensitive TreeMap

A common practical need: a TreeMap where keys are case-insensitive strings (useful for HTTP headers, config keys):

TreeMap<String, String> headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
headers.put("Content-Type", "application/json");
headers.put("content-type", "text/html"); // overwrites!

System.out.println(headers.get("CONTENT-TYPE")); // text/html
System.out.println(headers.size()); // 1

Null-Safe Comparator

Tree collections with natural ordering throw NPE for null keys. Use a null-safe comparator to allow null as the minimum key:

TreeMap<String, Integer> map = new TreeMap<>(
    Comparator.nullsFirst(Comparator.naturalOrder())
);
map.put(null, 0);
map.put("b", 2);
map.put("a", 1);

map.forEach((k,v) -> System.out.println(k + "=" + v));
// null=0, a=1, b=2

Domain Object Example: Product by Price

Sort products by price in a TreeSet, with name as tiebreaker to maintain uniqueness:

record Product(String name, double price) {}

TreeSet<Product> catalog = new TreeSet<>(
    Comparator.comparingDouble(Product::price)
              .thenComparing(Product::name)
);
catalog.add(new Product("Widget", 9.99));
catalog.add(new Product("Gadget", 24.99));
catalog.add(new Product("Donut",  9.99));

catalog.forEach(p -> System.out.println(p.name() + " $" + p.price()));
// Donut $9.99, Widget $9.99, Gadget $24.99

Retrieving the Comparator

Call comparator() on a TreeMap/TreeSet to retrieve the custom comparator. Returns null if natural ordering is used.

TreeMap<String, Integer> map = new TreeMap<>(Comparator.reverseOrder());
System.out.println(map.comparator() != null); // true

TreeMap<String, Integer> natural = new TreeMap<>();
System.out.println(natural.comparator());      // null

Comparator Composition

Java's Comparator offers chainable factory methods for clean composition:

Comparator<String> comp =
    Comparator.comparingInt(String::length)   // by length
              .thenComparing(Comparator.naturalOrder()); // then alphabetically

TreeSet<String> ts = new TreeSet<>(comp);
ts.addAll(List.of("go", "java", "c", "rust", "py"));
ts.forEach(s -> System.out.print(s + " "));
// c go py java rust

When NOT to Use a Custom Comparator

Avoid using a comparator that's inconsistent with equals on TreeMap keys/TreeSet elements — it causes confusing "missing" entries. Ensure compare(a, b) == 0 iff a.equals(b) for correct behavior in all collection contexts.

Quick Check

A TreeSet uses a comparator based on String::length only. What happens when you add both "cat" and "dog"?

Recap: Custom Ordering

Key takeaways:

  • Pass a Comparator to TreeMap/TreeSet constructor to define custom ordering
  • Comparator-defined equality governs uniqueness in tree collections
  • Ensure comparator consistency with equals to avoid surprises
  • Use Comparator.nullsFirst/nullsLast for null-safe ordering
  • Chain with thenComparing for multi-field sorting

Frequently asked questions

Is the “Custom Ordering in Tree Collections” lesson free?

Yes — the full text of “Custom Ordering in Tree Collections” is free to read here on the web, and the Java Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Java Academy course, upgrade to CoddyKit PRO.

What will I learn in “Custom Ordering in Tree Collections”?

Supply a Comparator to TreeMap/TreeSet to define domain-specific sort orders. You practise Java Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Java Academy?

No prior experience is required. Java Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Custom Ordering in Tree Collections” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Java Academy lesson?

Yes. Every Java Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. TreeMap: Sorted Key-Value Pairs
  2. Submaps and Range Views
  3. TreeSet and NavigableSet
  4. Custom Ordering in Tree Collections
← Back to Java Academy