Question
HashMap vs Hashtable in Java: Differences, Performance, and When to Use Each
Question
In Java, what are the differences between HashMap and Hashtable?
Which one is more efficient for applications that do not use multiple threads?
Short Answer
By the end of this page, you will understand how HashMap and Hashtable differ in Java, especially in terms of thread safety, performance, null handling, and typical usage. You will also know why HashMap is usually the better choice for non-threaded applications and what developers use instead of Hashtable in modern Java code.
Concept
HashMap and Hashtable are both Java classes used to store data as key-value pairs.
That means you can store a value and look it up later using a key:
Map<String, Integer> ages = new HashMap<>();
ages.put("Alice", 30);
Both classes are based on hash table data structures, so they are designed for fast lookup, insertion, and deletion.
Core differences
1. Thread safety
Hashtableis synchronized.HashMapis not synchronized.
This means Hashtable tries to make its methods safe when accessed by multiple threads at the same time. HashMap does not do that by default.
2. Performance
Because Hashtable synchronizes its methods, it usually has more overhead.
For non-threaded applications, HashMap is generally more efficient and faster.
3. Null keys and values
HashMapallows:- one
nullkey - multiple
nullvalues
- one
Hashtableallows:- no
nullkeys - no
nullvalues
- no
Example:
Map<String, String> map = new HashMap<>();
map.put(null, "hello");
map.put("x", null);
The same kind of code would throw a NullPointerException with Hashtable.
4. Legacy vs modern API
Hashtable is an older class from early Java. In modern Java code, developers usually prefer:
HashMapfor normal single-threaded useConcurrentHashMapfor high-performance thread-safe use
Because of that, Hashtable is now mostly considered a legacy class.
Why this matters
Choosing the right map affects:
- application speed
- thread safety
- how null values are handled
- code readability and maintainability
In real programs, HashMap is the default choice unless you specifically need concurrent access handling.
Mental Model
Think of a map as a labeled cabinet of drawers:
- The key is the label on the drawer.
- The value is what is stored inside.
Now imagine two versions of that cabinet:
HashMap: a normal cabinet that is quick to use, but two people opening and changing drawers at the same time may cause problems.Hashtable: a cabinet with a lock on nearly every action, making it safer for shared use, but slower because of the extra locking.
For one person using the cabinet alone, the locking adds unnecessary delay. That is why HashMap is usually better for non-threaded programs.
Syntax and Examples
Basic syntax
Using HashMap
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 90);
scores.put("Bob", 85);
System.out.println(scores.get("Alice"));
Using Hashtable
import java.util.Hashtable;
import java.util.Map;
Map<String, Integer> scores = new Hashtable<>();
scores.put("Alice", 90);
scores.put("Bob", 85);
System.out.println(scores.get("Alice"));
Both examples store and retrieve key-value pairs in a similar way.
Example showing a practical difference
import java.util.HashMap;
import java.util.Hashtable;
public class Main {
public static void main(String[] args) {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put(null, "Allowed");
hashMap.put("language", null);
System.out.println(hashMap);
Hashtable<String, String> hashtable = new Hashtable<>();
// hashtable.put(null, "Not allowed");
// hashtable.put("language", null);
}
}
What this shows
HashMapacceptsnullin certain cases.Hashtabledoes not.- In normal single-threaded code,
HashMapis usually the preferred option.
Common recommendation
Map<String, String> map = new HashMap<>();
This is common because:
Mapis the interfaceHashMapis the implementation- it makes code easier to change later if needed
Step by Step Execution
Consider this example:
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<String, Integer> inventory = new HashMap<>();
inventory.put("Pen", 10);
inventory.put("Book", 5);
inventory.put("Pen", 12);
System.out.println(inventory.get("Pen"));
System.out.println(inventory.get("Book"));
}
}
Step by step
1. Create the map
Map<String, Integer> inventory = new HashMap<>();
A new empty HashMap is created.
2. Add first entry
inventory.put("Pen", 10);
The key "Pen" is stored with the value 10.
3. Add second entry
inventory.put("Book", 5);
Now the map has two entries.
4. Add an entry with an existing key
inventory.put("Pen", 12);
The key "Pen" already exists, so the old value 10 is replaced with 12.
5. Read values
System.out.println(inventory.get("Pen"));
Prints:
12
And:
System.out.println(inventory.get("Book"));
Prints:
5
Important idea
A map does not keep duplicate keys. If you insert the same key again, the value is updated.
Real World Use Cases
HashMap and similar map structures are used everywhere in Java applications.
Common real uses
Configuration storage
Map<String, String> config = new HashMap<>();
config.put("host", "localhost");
config.put("port", "8080");
Useful for application settings.
Counting values
Map<String, Integer> wordCount = new HashMap<>();
wordCount.put("java", 3);
Useful for text processing, analytics, and reporting.
Caching lookups
A program may cache expensive results using a key so it can reuse them later.
Mapping IDs to objects
Map<Integer, String> users = new HashMap<>();
users.put(101, "Alice");
Useful in APIs, services, and in-memory data stores.
Fast lookup tables
Maps are often used when you need quick access to data by key rather than looping through a list.
Where Hashtable might appear
- older enterprise applications
- legacy libraries
- maintenance of old Java systems
In modern code, Hashtable is uncommon.
Real Codebase Usage
In real Java codebases, developers rarely choose Hashtable for new code.
Common modern patterns
1. Default to Map + HashMap
Map<String, String> headers = new HashMap<>();
This keeps code flexible and easy to refactor.
2. Use guard checks before reading values
if (headers.containsKey("Authorization")) {
System.out.println(headers.get("Authorization"));
}
This helps avoid mistakes when keys may be missing.
3. Use maps for validation and lookup rules
Map<String, Boolean> featureFlags = new HashMap<>();
featureFlags.put("newDashboard", true);
Useful for configuration and feature toggles.
4. Use getOrDefault
int count = wordCounts.getOrDefault("java", 0);
This is very common for counters and aggregation.
5. Use ConcurrentHashMap instead of Hashtable for concurrency
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
Map<String, Integer> sharedMap = new ConcurrentHashMap<>();
This is the typical modern replacement when multiple threads need shared access.
Practical recommendation
- Single-threaded: use
HashMap - Multi-threaded: usually use
ConcurrentHashMap - Legacy maintenance: understand
Hashtable, but avoid introducing it into new code unless required
Common Mistakes
1. Assuming Hashtable is always better because it is thread-safe
Being synchronized does not automatically make it the best choice.
For single-threaded programs, Hashtable usually adds unnecessary overhead.
2. Forgetting that Hashtable does not allow null
Broken example:
Hashtable<String, String> table = new Hashtable<>();
table.put(null, "value");
This throws a NullPointerException.
3. Thinking HashMap is safe for concurrent writes
Broken idea:
Map<String, Integer> map = new HashMap<>();
This is fine in one thread, but unsafe if many threads modify it without protection.
To avoid problems in concurrent code, use:
ConcurrentHashMap- external synchronization
4. Using the concrete class type everywhere
Less flexible:
HashMap<String, Integer> map = new HashMap<>();
Usually better:
Map<String, Integer> map = new HashMap<>();
Programming to the interface makes code easier to change.
5. Expecting insertion order
Neither HashMap nor Hashtable guarantees insertion order.
If order matters, consider LinkedHashMap.
6. Confusing missing keys with null values
With HashMap, this can be tricky because get(key) may return null either because:
- the key is missing, or
- the key exists but maps to
null
Use containsKey() when needed.
Comparisons
| Feature | HashMap | Hashtable |
|---|---|---|
| Thread-safe by default | No | Yes |
| Synchronized methods | No | Yes |
Allows null key | Yes, one | No |
Allows null values | Yes | No |
| Performance in single-threaded code | Usually faster | Usually slower |
| Legacy class | No | Yes |
| Common in modern Java | Yes | Rarely |
| Better modern concurrent alternative | ConcurrentHashMap | ConcurrentHashMap |
HashMap vs ConcurrentHashMap
| Feature | HashMap | ConcurrentHashMap |
|---|---|---|
| Thread-safe | No | Yes |
| Good for single-threaded code | Yes | Usually unnecessary |
| Good for concurrent code | No | Yes |
Allows null keys/values | Yes | No |
Quick conclusion
- Choose
HashMapfor non-threaded applications. - Avoid
Hashtablein new code unless you must work with legacy APIs. - Use
ConcurrentHashMapwhen thread safety is needed.
Cheat Sheet
Map<String, Integer> map = new HashMap<>();
Map<String, Integer> table = new Hashtable<>();
Key rules
HashMapis not synchronized.Hashtableis synchronized.HashMapallows:- one
nullkey - multiple
nullvalues
- one
Hashtableallows:- no
nullkeys - no
nullvalues
- no
- For non-threaded applications,
HashMapis usually faster. Hashtableis a legacy class.- For thread-safe modern code, prefer
ConcurrentHashMap.
Common operations
map.put("A", 1);
map.get("A");
map.containsKey("A");
map.remove("A");
map.getOrDefault("B", 0);
Best practice
Map<String, Integer> map = new HashMap<>();
Watch out for
- no ordering guarantee
- duplicate keys replace old values
get()may returnnullHashtablethrowsNullPointerExceptionfor null keys or values
FAQ
Is HashMap faster than Hashtable in Java?
Yes, in most single-threaded cases HashMap is faster because it does not synchronize every method.
Why is Hashtable considered legacy?
It comes from older Java APIs and has mostly been replaced by better choices such as HashMap and ConcurrentHashMap.
Should I use Hashtable in new Java code?
Usually no. Use HashMap for normal use and ConcurrentHashMap when you need thread safety.
Can HashMap store null keys and values?
Yes. It allows one null key and multiple null values.
Can Hashtable store null keys or null values?
No. It throws NullPointerException if you try.
What should I use in a multi-threaded Java application?
In most cases, use ConcurrentHashMap instead of Hashtable.
Do HashMap and Hashtable preserve insertion order?
No. If you need insertion order, use LinkedHashMap.
Which one should I use for a non-threaded application?
Use HashMap. It is the standard and more efficient choice for that situation.
Mini Project
Description
Build a small Java program that stores product stock levels using a map. This project demonstrates why HashMap is a practical default for single-threaded applications and helps you practice basic map operations such as put, get, containsKey, and getOrDefault.
Goal
Create a simple inventory tracker that stores item names and quantities using HashMap.
Requirements
[ "Create a map that stores product names as keys and stock quantities as values.", "Add at least three products to the inventory.", "Update the quantity of an existing product.", "Print the quantity of a product by its name.", "Print a default value when a product does not exist." ]
Keep learning
Related questions
Add External JAR Files to an IntelliJ IDEA Java Project
Learn how to add external JAR dependencies to an IntelliJ IDEA Java project using module libraries, and when to use Maven or Gradle instead.
Avoiding Java Code in JSP with JSP 2: EL and JSTL Explained
Learn how to avoid Java scriptlets in JSP 2 using Expression Language and JSTL, with examples, best practices, and common mistakes.
Call a Method After a Delay in Android Java
Learn how to run Java code after a delay in Android using Handler.postDelayed, manage the main thread, and cancel callbacks safely.