Before HashMap and the Java Collections Framework revolutionized data handling, Java provided Hashtable and Properties classes for key-value mapping. Though largely considered legacy, these classes still play a role in configuration management and backward compatibility.
In this tutorial, you'll learn how Hashtable and Properties work, how they differ from modern collections, when to use them (or not), and how to modernize legacy codebases using Java 8+ best practices.
Table of Contents
- What are Hashtable and Properties?
- Java Syntax and Class Structure
- Internal Working and Thread-Safety Model
- Performance Benchmarks and Big-O Complexity
- Real-World Use Cases in Legacy and Modern Code
- Functional Programming in Java 8+
- Java Version Enhancements (Java 8–21)
- Comparisons with Other Maps
- Pros and Cons
- Anti-patterns and Misuse Cases
- Refactoring Legacy Code
- Best Practices
- 📌 What's New in Java [version]?
- Conclusion and Key Takeaways
- FAQ – 10 Expert-Level Questions
What are Hashtable and Properties?
Hashtable
- Part of the original Java 1.0 release
- Implements
Map<K, V>interface (since Java 2) - Synchronized by default → thread-safe
Properties
- Subclass of
Hashtable<Object, Object> - Specializes in managing configuration with
Stringkeys and values - Commonly used for
.propertiesfile handling
Properties config = new Properties();
config.setProperty("host", "localhost");
String host = config.getProperty("host");
Java Syntax and Class Structure
Hashtable<String, Integer> table = new Hashtable<>();
table.put("A", 1);
table.get("A");
Properties props = new Properties();
props.setProperty("key", "value");
Internal Working and Thread-Safety Model
Hashtable
- Internally uses an array of buckets + chaining (linked list)
- Synchronized methods: every operation locks the entire object
- Resize logic similar to
HashMap(but less optimized)
Properties
- Extends
Hashtable<Object, Object> - Offers
load()andstore()methods to read/write.propertiesfiles
props.load(new FileReader("config.properties"));
props.store(new FileWriter("config.properties"), "App Config");
Performance Benchmarks
| Operation | Hashtable | HashMap | ConcurrentHashMap |
|---|---|---|---|
| get/put | O(1) | O(1) | O(1) (segmented) |
| Synchronization | Full | None | Fine-grained |
| Usage | Legacy | General use | Multi-threaded env |
Real-World Use Cases
- Reading Java configuration files (Properties)
- Legacy enterprise codebases (Hashtable)
- Java desktop apps using
.propertiesfor UI strings
Functional Programming Support
While Hashtable supports the Map interface, it is less optimized for modern idioms. Example with Java 8:
Hashtable<String, Integer> table = new Hashtable<>();
table.put("X", 1);
table.put("Y", 2);
table.forEach((k, v) -> System.out.println(k + " = " + v));
Java Version Enhancements
Java 8
- Stream API applies to
entrySet() forEach(),compute(), etc., work onHashtable
Java 9+
Map.of()offers better alternatives for static configPropertiesenhancements remain minimal
Java 10–21
- No major changes to these legacy classes
- Still supported for backward compatibility
Comparisons with Other Maps
| Feature | Hashtable | HashMap | Properties |
|---|---|---|---|
| Thread-safe | Yes (full sync) | No | Yes |
| Null keys/values | None allowed | One null key, many null values | No nulls |
| Performance | Slower | Fast | Slower |
| Usage | Legacy code | Modern standard | Config handling |
Pros and Cons
✅ Pros
- Simple, familiar for legacy codebases
Propertiesis great for config files- Thread-safe without extra wrappers
❌ Cons
- Slower due to global synchronization
- Not optimized for modern performance needs
- Doesn't support nulls (adds boilerplate)
Anti-patterns and Misuse Cases
❌ Using Hashtable for new code
Use HashMap or ConcurrentHashMap instead.
❌ Storing non-string values in Properties
props.put("port", 8080); // Incorrect: should use setProperty()
❌ Using Hashtable in high-throughput systems
Rewriting with ConcurrentHashMap is recommended.
Refactoring Legacy Code
Before:
Hashtable<String, String> users = new Hashtable<>();
After (modern):
Map<String, String> users = Collections.synchronizedMap(new HashMap<>());
Or better for concurrency:
Map<String, String> users = new ConcurrentHashMap<>();
Best Practices
- Prefer
HashMaporConcurrentHashMapunless legacy compatibility is needed - Use
Propertiesstrictly for loading/saving config files - Always wrap
FileReader/Writerin try-with-resources
📌 What's New in Java [version]?
Java 8
- Added
forEach(),compute(),merge()to Map interface
Java 9
Map.of()as alternative toPropertiesfor static config
Java 10+
varfor local variable declarations
Java 21
- No specific enhancements to
HashtableorProperties
Conclusion and Key Takeaways
HashtableandPropertiesare part of Java’s legacy Map infrastructure.- Still useful for maintaining compatibility or handling simple configuration.
- Should be avoided in new development in favor of more modern, performant alternatives.
- Java 8+ features make transition easier with minimal code rewrite.
FAQ – 10 Expert-Level Questions
1. Why use Hashtable instead of HashMap?
Only if legacy compatibility or full synchronization is required.
2. Is Hashtable faster than ConcurrentHashMap?
No. ConcurrentHashMap is more scalable under concurrency.
3. Can Properties hold non-String types?
It can, but getProperty() only works for strings. Use carefully.
4. Can Hashtable store null keys or values?
No. Both keys and values must be non-null.
5. How is Properties used in Spring or Java EE?
Frequently used to externalize configuration (application.properties).
6. Can I iterate Properties like a map?
Yes, via entrySet() inherited from Hashtable.
7. What's the best alternative to Hashtable?
Use ConcurrentHashMap for thread safety, or HashMap otherwise.
8. Are Properties files Unicode-compatible?
Yes, but escaped via \uXXXX format when saved in ISO-8859-1.
9. How to read from a .properties file safely?
Use try-with-resources and catch IOException.
10. Should I remove all Hashtable usage in codebase?
Yes, unless a third-party library depends on it. Refactor using modern collections.