Choose TreeMap when you need ordered iteration, range queries, nearest-match lookups, or a deterministic key order in output. Otherwise stick with HashMap — it's faster (O(1) vs O(log n)) and uses less memory per entry.
The decision matrix
| Operation | Best | Average | Worst | Note |
|---|---|---|---|---|
| get / put / remove | HashMap: O(1) avg | HashMap wins | TreeMap: O(log n) | Plain key lookup -> HashMap |
| iterate in key order | TreeMap: O(n) | TreeMap wins | HashMap: O(n log n) (sort) | Sorted output -> TreeMap |
| range query [a, b) | TreeMap: O(log n + k) | TreeMap wins | HashMap: O(n) | TreeMap.subMap is built for this |
| nearest-match (floor/ceiling) | TreeMap: O(log n) | TreeMap wins | HashMap: O(n) | HashMap has no equivalent |
| memory per entry | HashMap: smaller | HashMap wins | TreeMap: parent/left/right/color | Tree entries are heavier |
Pick TreeMap when…
- You need deterministic iteration order. Logs, reports, JSON serialisation where consumers expect sorted keys.
LinkedHashMapis an alternative if you want insertion order;TreeMapis the choice for natural or custom order. - You query by range or proximity. Time series, leaderboards, pricing tiers, IP ranges, geometric intervals. The
subMap,floorEntry, andceilingEntrymethods are O(log n) and have noHashMapanalogue. - You need to find the largest/smallest key quickly.
firstKey/lastKeyare O(log n) (root-to-leaf descent). On aHashMap, the equivalent is an O(n) scan. - You want a sorted output without explicitly sorting.
treeMap.keySet()is already sorted; you save theO(n log n)sort step.
Stick with HashMap when…
- You only do lookups by exact key. The constant-factor difference is real —
HashMapis often 5-10x faster per operation in tight loops. - Keys don't have a natural order (or you don't want to define one).
TreeMaprequires eitherComparablekeys or aComparator.HashMaponly needshashCode/equals. - You're optimising memory.
TreeMap.Entrycarriesparent,left,right,color— three pointers and a boolean per entry, plus less array packing. For millions of entries,HashMapwins by a comfortable margin.
A worked example
// HashMap: O(n log n) to print in sorted order
Map<String, Integer> hm = new HashMap<>();
hm.put("banana", 2); hm.put("apple", 5); hm.put("cherry", 1);
hm.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.forEach(e -> System.out.println(e.getKey() + "=" + e.getValue()));
// TreeMap: O(n) — already sorted
Map<String, Integer> tm = new TreeMap<>(hm);
tm.forEach((k, v) -> System.out.println(k + "=" + v));
What about ConcurrentSkipListMap?
If you want TreeMap semantics in a concurrent setting, use ConcurrentSkipListMap. It implements the full NavigableMap API, is lock-free, and offers comparable O(log n) performance — at the cost of higher per-operation constants than TreeMap.