TreeMap stores mappings in key order and exposes range and nearest-key operations through the NavigableMap contract.
Java TreeMap: ordered keys and range views
Search an ordered domain
Hashing answers exact lookup. A pricing schedule has a different question: which threshold is the greatest one not above this order quantity? floorEntry answers it directly. The keys are thresholds, not individual purchases.
Natural ordering works for integer thresholds. A custom comparator changes the definition of key uniqueness: keys that compare as zero occupy the same mapping even if equals says otherwise. Keep those contracts consistent unless the disagreement is intentional and documented.
For a case-insensitive string comparator, two differently capitalised strings can address the same mapping. This can be useful for a lookup, but it is unsuitable when the original identifiers must remain distinct. Compare the contract with HashMap before replacing a storage type.
Range views share storage
subMap produces a view of the parent map, not an independent snapshot. Changes through either side can be visible through the other. Copy into a new map when a reader needs a stable snapshot owned by that reader.
The four-argument overload makes inclusive and exclusive endpoints explicit. A threshold exactly equal to the lower bound belongs in an inclusive range; one equal to an exclusive upper bound does not.
floorEntry can return null. An order below the smallest configured threshold has no matching rule. The program checks that case rather than converting absence into a zero price.
Working program
import java.util.Map;
import java.util.NavigableMap;
import java.util.TreeMap;
public class QuantityPricing {
public static void main(String[] args) {
NavigableMap<Integer, Integer> centsPerUnit = new TreeMap<>();
centsPerUnit.put(1, 240);
centsPerUnit.put(10, 220);
centsPerUnit.put(50, 195);
int quantity = 24;
Map.Entry<Integer, Integer> price = centsPerUnit.floorEntry(quantity);
if (price == null) {
throw new IllegalArgumentException("Quantity must meet a threshold");
}
System.out.println("unitCents=" + price.getValue());
System.out.println("thresholds=" + centsPerUnit.subMap(10, true, 50, false).keySet());
}
}Output
unitCents=220
thresholds=[10]Cost and design choices
Key lookup, insertion, and removal require O(log n) tree work for n entries, assuming key comparisons have bounded cost. Returning a range view does not copy every mapping. Traversing k selected mappings still costs work proportional to those visited entries.
Tree nodes allocate references and metadata per entry. A sorted array can use less memory for an immutable small schedule, but insertion into that representation requires moving elements. Match the representation to the update rate.
Prices use integer cents here so the example isolates threshold selection. A real multi-currency pricing engine must define currency, rounding, tax, and bounds; BigDecimal addresses decimal arithmetic, not those policy choices.
Common Mistakes
- Do not dereference a missing floorEntry.
- Do not assume a subMap is a detached copy.
- Do not insert keys that your comparator cannot compare, including null when unsupported.
Connect the contracts
Compare the boundary explained in Comparator rules with the assumptions made by this program.
Extend the tested workflow
Continue with Java NavigableMap ranges: distinguish a live window from a snapshot.
