Question

HashMap vs Hashtable in Java: Differences, Performance, and When to Use Each

javacollectionshashmaphashtable

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

  • Hashtable is synchronized.
  • HashMap is 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

  • HashMap allows:
    • one null key
    • multiple null values
  • Hashtable allows:
    • no null keys
    • no null values

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:

  • HashMap for normal single-threaded use
  • ConcurrentHashMap for 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.

Take Quiz

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

  • HashMap accepts null in certain cases.
  • Hashtable does not.
  • In normal single-threaded code, HashMap is usually the preferred option.

Common recommendation

Map<String, String> map = new HashMap<>();

This is common because:

  • Map is the interface
  • HashMap is 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.

Take Quiz

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

FeatureHashMapHashtable
Thread-safe by defaultNoYes
Synchronized methodsNoYes
Allows null keyYes, oneNo
Allows null valuesYesNo
Performance in single-threaded codeUsually fasterUsually slower
Legacy classNoYes
Common in modern JavaYesRarely
Better modern concurrent alternativeConcurrentHashMapConcurrentHashMap

HashMap vs ConcurrentHashMap

FeatureHashMapConcurrentHashMap
Thread-safeNoYes
Good for single-threaded codeYesUsually unnecessary
Good for concurrent codeNoYes
Allows null keys/valuesYesNo

Quick conclusion

  • Choose HashMap for non-threaded applications.
  • Avoid Hashtable in new code unless you must work with legacy APIs.
  • Use ConcurrentHashMap when thread safety is needed.
Take Quiz

Cheat Sheet

Map<String, Integer> map = new HashMap<>();
Map<String, Integer> table = new Hashtable<>();

Key rules

  • HashMap is not synchronized.
  • Hashtable is synchronized.
  • HashMap allows:
    • one null key
    • multiple null values
  • Hashtable allows:
    • no null keys
    • no null values
  • For non-threaded applications, HashMap is usually faster.
  • Hashtable is 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 return null
  • Hashtable throws NullPointerException for 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.

Take Quiz

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." ]

Take Quiz

Keep learning

Related questions

View more