替换java.util.Properties为TreeMap?大型国际化资源文件性能优化咨询
Great question—let's break this down based on your specific needs: read-only access, maximum lookup speed, willingness to trade memory for performance, and keys with shared prefixes that are sortable.
Should you switch to TreeMap?
Short answer: Probably not. Here's why:
- TreeMap uses a red-black tree under the hood, so every lookup takes O(log n) time. Even when HashMap treeifies its linked lists (for entries with poor hash distribution), its average case is still O(1) for most lookups—way faster than TreeMap's consistent O(log n) overhead.
- Your keys are sortable, but since you only need
get()operations, TreeMap's ordered traversal capabilities are wasted. - Memory-wise, TreeMap doesn't offer any advantages over HashMap here; in fact, each tree node has more overhead (parent/left/right pointers) than HashMap's entry objects.
Stick with HashMap (or its optimized variants) before reaching for TreeMap.
What about optimized HashMap alternatives?
If you want to stick to a hash-based map but squeeze out more performance:
- Use an immutable HashMap implementation: Libraries like Guava's
ImmutableMapor Java 11+'sMap.copyOf()create hash tables optimized for read-only access. They skip overhead for mutation support, use tighter memory layouts, and avoid treeification entirely (since they're built from scratch with good hash distribution). For large datasets, this can be significantly faster than a standard HashMap. - Tweak HashMap parameters: If you're using a standard HashMap, bump up the load factor (e.g., to 1.0) and initialize it with a capacity matching your entry count. This reduces the number of rehashes and improves cache locality—perfect if you're willing to trade memory for speed. Just make sure your keys have a good hash function (which
Stringdoes, so your "button.*" keys should distribute well). - Skip
ConcurrentHashMap: You don't need thread-safe updates, so the synchronization overhead here is unnecessary.
Trie-based implementations: The perfect fit for your prefix-heavy keys?
Absolutely—this is where you'll see the biggest performance gains for your specific key pattern.
Tries (or radix trees, like Patricia Tries) are designed for keys with shared prefixes. Instead of hashing the entire key, they traverse characters one by one, leveraging shared prefixes to save memory and speed up lookups. For your use case:
- Lookup time is O(k) where k is the length of the key (not the number of entries), which is faster than both HashMap and TreeMap for large datasets.
- Memory efficiency is great because duplicate prefixes (like "button.") are stored once, not per entry. This might even use less memory than HashMap despite your willingness to trade memory for speed.
- If you ever need to do prefix-based queries (e.g., get all keys starting with "button."), tries can do this in O(k + m) time (m = number of matching entries) without iterating the entire map—something HashMap can't do efficiently.
For Java, the go-to implementation is Apache Commons Collections' PatriciaTrie—it's a compressed radix tree that's optimized for read performance and memory usage. Alternatively, you could build a custom read-only trie tailored exactly to your keys (since you don't need updates, you can pre-construct it once from your Properties file and lock it down).
Final Recommendations
Based on your priorities:
- Maximize raw lookup speed with prefix-heavy keys: Use
PatriciaTrie(Apache Commons Collections) or a custom read-only trie. This is the optimal choice for your key pattern. - Simplest high-performance drop-in replacement: Use Guava's
ImmutableMapor a tuned standard HashMap (high load factor, pre-sized capacity). - Avoid TreeMap: It doesn't offer performance benefits for your read-only, lookup-focused use case.
内容的提问来源于stack exchange,提问作者Sergey Ponomarev

