00:00

Difference Between HashSet and HashMap in Java

HashSet and HashMap are both hash-table-based collections with O(1) average lookups, but they store different things:

  • A HashSet stores individual unique values, answering "is this element present?". It implements Set.
  • A HashMap stores key–value pairs with unique keys, answering "what value belongs to this key?". It implements Map.

In fact, HashSet is implemented using a HashMap internally.

1. Comparison Table

AspectHashSetHashMap
InterfaceSet<E> (a Collection)Map<K, V> (not a Collection)
StoresSingle elementsKey–value pairs (entries)
DuplicatesNo duplicate elementsNo duplicate keys; values may repeat
Addingadd(e) returns false for a duplicateput(k, v) replaces and returns the old value
Lookupcontains(e)get(k), containsKey, containsValue
NullOne null elementOne null key, any number of null values
Internal structureA HashMap with elements as keys and a dummy valueArray of buckets (lists, or trees when crowded)
IterationOver elementsOver keySet(), values() or entrySet()
OrderNot guaranteedNot guaranteed
Thread-safeNoNo

2. Using Both

SetVsMap.java
import java.util.*;

public class SetVsMap {
    public static void main(String[] args) {
        // HashSet: stores single values, unique
        Set<String> visitors = new HashSet<>();
        System.out.println("add asha : " + visitors.add("asha"));
        System.out.println("add asha : " + visitors.add("asha") + "  (duplicate rejected)");
        visitors.add("ravi");
        System.out.println("visitors : " + visitors.size() + ", contains ravi? " + visitors.contains("ravi"));

        // HashMap: stores key -> value pairs, keys unique, values may repeat
        Map<String, Integer> visits = new HashMap<>();
        System.out.println("put asha : " + visits.put("asha", 1));          // null: no previous value
        System.out.println("put asha : " + visits.put("asha", 2) + "  (old value returned, replaced)");
        visits.put("ravi", 2);                                               // duplicate VALUE is fine
        visits.merge("ravi", 1, Integer::sum);                               // count up
        System.out.println("visits   : asha=" + visits.get("asha") + ", ravi=" + visits.get("ravi"));
        System.out.println("keySet is a Set: " + (visits.keySet() instanceof Set));
        visits.put(null, 0);                    // HashMap: one null key allowed
        visitors.add(null);                     // HashSet: one null element allowed
        System.out.println("null key: " + visits.containsKey(null) + ", null element: " + visitors.contains(null));
    }
}
Output
add asha : true
add asha : false  (duplicate rejected)
visitors : 2, contains ravi? true
put asha : null
put asha : 1  (old value returned, replaced)
visits   : asha=2, ravi=3
keySet is a Set: true
null key: true, null element: true

Both rely on hashCode() and equals() of the elements or keys, so these must be implemented consistently.

3. How HashSet Uses a HashMap

Inside HashSet is a field HashMap<E, Object> map. add(e) calls map.put(e, PRESENT), where PRESENT is a shared dummy object, and returns true if the previous value was null. The program below shows the idea, along with a problem suited to each structure:

BackedByMap.java
import java.util.*;

public class BackedByMap {
    public static void main(String[] args) {
        // Conceptually, HashSet is a HashMap whose keys are the elements
        // and whose values are a shared dummy object (PRESENT).
        Map<String, Object> asMap = new HashMap<>();
        Object PRESENT = new Object();
        for (String s : List.of("red", "green", "red")) asMap.put(s, PRESENT);
        Set<String> asSet = new HashSet<>(List.of("red", "green", "red"));
        System.out.println("map keys: " + new TreeSet<>(asMap.keySet()) + ", set: " + new TreeSet<>(asSet));

        // Word frequency: a natural Map problem; unique words: a natural Set problem
        String text = "to be or not to be";
        Map<String, Integer> freq = new TreeMap<>();
        Set<String> unique = new TreeSet<>();
        for (String w : text.split(" ")) { freq.merge(w, 1, Integer::sum); unique.add(w); }
        System.out.println("frequency: " + freq);
        System.out.println("unique   : " + unique);
    }
}
Output
map keys: [green, red], set: [green, red]
frequency: {be=2, not=1, or=1, to=2}
unique   : [be, not, or, to]

4. When to Use Which

  • HashSet: removing duplicates, tracking visited items, checking membership, set operations (union, intersection).
  • HashMap: looking up data by an identifier, counting occurrences, caching, grouping values by key.

Need ordering? Use LinkedHashSet/LinkedHashMap (insertion order) or TreeSet/TreeMap (sorted). Need thread safety? Use ConcurrentHashMap and ConcurrentHashMap.newKeySet().

5. Summary

  • HashSet stores unique values; HashMap stores unique keys mapped to values.
  • add ignores duplicates; put replaces the value of an existing key.
  • HashSet is backed by a HashMap with a dummy value.
  • Both give O(1) average operations, no ordering guarantee and no thread safety.

Related Tutorials