In Java, ordered collections that allow navigation and range views are powered by two powerful interfaces: NavigableMap
and NavigableSet
. These are advanced extensions of SortedMap
and SortedSet
that provide fine-grained control over ordering, range queries, and element access.
If you've ever needed to find the closest value lower or higher than a key, or fetch a subset of elements within a range, then NavigableMap
and NavigableSet
are for you. Understanding these APIs can greatly enhance your ability to build efficient and readable logic for real-world systems like search engines, cache indexes, scheduling, or stock price analysis.
NavigableMap – Definition and Purpose
What Is It?
NavigableMap<K, V>
extends SortedMap<K, V>
and provides navigation methods such as lowerEntry()
, floorEntry()
, ceilingEntry()
, higherEntry()
, and view-returning methods like headMap()
and tailMap()
.
Common Implementation
NavigableMap<Integer, String> map = new TreeMap<>();
Key Methods
Method | Description |
---|---|
lowerEntry(key) |
Entry less than the given key |
floorEntry(key) |
Entry ≤ given key |
ceilingEntry(key) |
Entry ≥ given key |
higherEntry(key) |
Entry greater than key |
headMap(key, inclusive) |
Submap strictly less or up to key |
tailMap(key, inclusive) |
Submap from key onwards |
descendingMap() |
Reversed view of the map |
Example
TreeMap<Integer, String> scores = new TreeMap<>();
scores.put(90, "A");
scores.put(80, "B");
scores.put(70, "C");
System.out.println(scores.floorEntry(85)); // 80=B
System.out.println(scores.ceilingEntry(85)); // 90=A
NavigableSet – Definition and Purpose
What Is It?
NavigableSet<E>
extends SortedSet<E>
and supports navigation-based methods like lower()
, floor()
, ceiling()
, higher()
.
Common Implementation
NavigableSet<Integer> set = new TreeSet<>();
Key Methods
Method | Description |
---|---|
lower(e) |
Greatest element < e |
floor(e) |
Greatest element ≤ e |
ceiling(e) |
Least element ≥ e |
higher(e) |
Least element > e |
headSet(e, inclusive) |
Elements < or ≤ e |
tailSet(e, inclusive) |
Elements ≥ or > e |
descendingSet() |
Reversed view of the set |
Example
TreeSet<Integer> numbers = new TreeSet<>();
numbers.addAll(List.of(10, 20, 30, 40));
System.out.println(numbers.lower(25)); // 20
System.out.println(numbers.higher(25)); // 30
Internal Working and Performance
Both interfaces are backed by balanced binary search trees (usually Red-Black Tree via TreeMap
and TreeSet
), ensuring O(log n) time complexity for most operations.
Operation | Time Complexity |
---|---|
insert/delete | O(log n) |
floor/ceiling | O(log n) |
iteration | O(n) |
Real-World Use Cases
- Leaderboard systems – Retrieve top N scores (
descendingMap().entrySet()
) - Event scheduling – Use
ceilingEntry()
to find the next event - Range queries – Analyze stock prices in a given time window
- Autocomplete systems – Use
tailSet(prefix)
to get suggestions
Java Syntax and Functional Examples
NavigableMap<Integer, String> map = new TreeMap<>();
map.put(1, "One");
map.put(2, "Two");
map.put(3, "Three");
map.subMap(1, true, 2, true) // includes 1 and 2
.forEach((k, v) -> System.out.println(k + " => " + v));
NavigableSet<String> set = new TreeSet<>();
set.addAll(List.of("apple", "banana", "mango"));
set.tailSet("banana", true)
.forEach(System.out::println); // banana, mango
Java Version Tracker
📌 What's New in Java?
- Java 8
- Introduced functional support (
forEach
, Streams) - Seamless integration with
entrySet().stream()
andfilter()
- Introduced functional support (
- Java 9
Map.of()
and immutable collections (though not Navigable)
- Java 10+
- Type inference (
var
) makes syntax cleaner
- Type inference (
- Java 21
- No direct enhancements to NavigableMap/Set, but TreeMap performance improves indirectly via GC enhancements and CPU optimizations
Comparisons
Feature | NavigableMap | NavigableSet |
---|---|---|
Backed by | TreeMap | TreeSet |
Type | Map<K, V> | Set |
Range views | headMap, tailMap | headSet, tailSet |
Floor/Ceiling methods | Yes | Yes |
Key-based lookup | Yes (K → V) | No (value-only) |
Reverse order view | descendingMap() | descendingSet() |
Best Practices
- Use
TreeMap
/TreeSet
only when ordering matters; else preferHashMap
/HashSet
- Leverage
subMap()
andheadMap()
for range queries instead of manual iteration - Be cautious when modifying maps/sets during iteration
- Use immutability wrappers if sharing maps across threads (
Collections.unmodifiableMap()
)
Anti-Patterns to Avoid
- Using
NavigableMap
for key types without natural ordering or a customComparator
- Forgetting that
subMap()
views are backed — changes affect the original map - Using
floor()
/ceiling()
on empty collections — may returnnull
or throw
Refactoring Legacy Code
- Replace manual sorted array or list search logic with
NavigableMap
methods (ceilingEntry
,floorEntry
) - Convert nested
if
conditions checking range intosubMap()
ortailMap()
Functional Programming with Streams
TreeMap<Integer, String> map = new TreeMap<>();
map.put(10, "ten");
map.put(20, "twenty");
map.entrySet()
.stream()
.filter(e -> e.getKey() > 15)
.forEach(System.out::println);
TreeSet<String> set = new TreeSet<>(List.of("A", "B", "C"));
set.stream()
.map(String::toLowerCase)
.forEach(System.out::println);
Conclusion and Key Takeaways
NavigableMap
andNavigableSet
offer powerful tools for sorted, navigable collections.- Use them when ordering and range queries are key to your logic.
- Understand that these interfaces are not replacements for HashMap/HashSet, but specialized alternatives.
- Leverage methods like
floor()
,ceiling()
,headMap()
for precise control over data access.
FAQ – NavigableMap and NavigableSet
-
Can I use null keys in NavigableMap?
No.TreeMap
(most common impl.) does not allow null keys. -
What’s the difference between headMap and tailMap?
headMap()
gives entries less than a key;tailMap()
gives entries from the key onward. -
Do these interfaces maintain insertion order?
No. They maintain natural or comparator-based sorted order. -
Are the views like subMap() backed or copied?
They’re backed views — changes reflect in the original structure. -
Can I use these in concurrent environments?
Not directly. UseConcurrentSkipListMap
or sync wrappers. -
Are floorEntry() and floor() the same?
Yes, butfloorEntry()
returns a map entry;floor()
returns just the value (or key in sets). -
How do I reverse the order?
UsedescendingMap()
ordescendingSet()
. -
What’s the performance difference with HashMap?
HashMap
is faster for key-value access;TreeMap
offers ordered navigation at a small cost. -
Can I serialize TreeMap/TreeSet?
Yes, both implementSerializable
. -
What happens on duplicate keys in NavigableMap?
New values replace old ones; keys remain unique.