Use cases for floorKey, ceilingKey, higherKey, lowerKey. — Cracked Java
// Java Collections Framework · TreeMap, NavigableMap, SortedMap
MidTheoryCodingGoogle

Use cases for floorKey, ceilingKey, higherKey, lowerKey.

floorKey, ceilingKey, higherKey, lowerKey are O(log n) nearest-match lookups. They shine for range queries, time-windowed lookups, bucket-by-threshold logic, and any scenario where the exact key may not exist but the closest one does.

The four operations

For a key k in a NavigableMap:

MethodReturnsInclusive?
floorKey(k)largest key ≤ kyes (key itself counts)
ceilingKey(k)smallest key ≥ kyes
lowerKey(k)largest key strictly < kno
higherKey(k)smallest key strictly > kno

All return null if no such key exists.

Use case: time-bucketed event lookup

Suppose you're tracking system events keyed by timestamp and want "what was the most recent event at or before time T?":

NavigableMap<Instant, Event> events = new TreeMap<>();
events.put(Instant.parse("2026-05-27T09:00:00Z"), new Event("startup"));
events.put(Instant.parse("2026-05-27T09:15:00Z"), new Event("config-loaded"));
events.put(Instant.parse("2026-05-27T09:45:00Z"), new Event("first-request"));

Instant query = Instant.parse("2026-05-27T09:30:00Z");
Map.Entry<Instant, Event> mostRecent = events.floorEntry(query);
// -> (09:15:00Z, config-loaded)

With a HashMap, you'd have to scan every key, sort by timestamp, and binary-search the result — O(n) per query. TreeMap.floorEntry is O(log n).

Use case: pricing tiers (find the right band)

// price thresholds -> discount rate
NavigableMap<Integer, BigDecimal> tiers = new TreeMap<>();
tiers.put(0,     new BigDecimal("0.00"));
tiers.put(100,   new BigDecimal("0.05"));
tiers.put(500,   new BigDecimal("0.10"));
tiers.put(1000,  new BigDecimal("0.15"));

int orderTotal = 750;
BigDecimal discount = tiers.floorEntry(orderTotal).getValue();
// 750 -> uses tier 500 -> 0.10 (10%)

The "floor" semantics map naturally onto "give me the largest tier ≤ this amount".

Use case: a range scan over a window

Combine navigation with subMap for windowed iteration:

Instant from = Instant.now().minus(Duration.ofMinutes(5));
Instant to   = Instant.now();

events.subMap(from, true, to, true)
      .forEach((t, e) -> log.info("{} -> {}", t, e));

The subMap view is O(1) to construct; iteration over it is O(k + log n) where k is the number of entries in the window.

Floor vs lower (and why both exist)

NavigableMap<Integer, String> m = new TreeMap<>();
m.put(10, "ten");

m.floorKey(10);  // 10  (<=)
m.lowerKey(10);  // null (strictly <)
m.ceilingKey(10);// 10  (>=)
m.higherKey(10); // null (strictly >)

The strict variants matter when you want "the previous entry" or "the next entry" excluding the query itself — e.g. paging through events in order.

Mark your status