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
HashSetstores individual unique values, answering "is this element present?". It implementsSet. - A
HashMapstores key–value pairs with unique keys, answering "what value belongs to this key?". It implementsMap.
In fact, HashSet is implemented using a HashMap internally.
1. Comparison Table
| Aspect | HashSet | HashMap |
|---|---|---|
| Interface | Set<E> (a Collection) | Map<K, V> (not a Collection) |
| Stores | Single elements | Key–value pairs (entries) |
| Duplicates | No duplicate elements | No duplicate keys; values may repeat |
| Adding | add(e) returns false for a duplicate | put(k, v) replaces and returns the old value |
| Lookup | contains(e) | get(k), containsKey, containsValue |
| Null | One null element | One null key, any number of null values |
| Internal structure | A HashMap with elements as keys and a dummy value | Array of buckets (lists, or trees when crowded) |
| Iteration | Over elements | Over keySet(), values() or entrySet() |
| Order | Not guaranteed | Not guaranteed |
| Thread-safe | No | No |
2. Using Both
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));
}
}
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:
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);
}
}
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
HashSetstores unique values;HashMapstores unique keys mapped to values.addignores duplicates;putreplaces the value of an existing key.HashSetis backed by aHashMapwith a dummy value.- Both give O(1) average operations, no ordering guarantee and no thread safety.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What is the main difference between HashSet and HashMap?
HashSet stores unique individual elements; HashMap stores key–value pairs with unique keys.
Q2. Does HashSet use HashMap internally?
Yes. Elements are stored as keys of an internal HashMap, each mapped to a constant dummy value.
Q3. Which is faster?
They have the same O(1) average performance, since HashSet delegates to a HashMap.
Q4. Can HashMap have duplicate values?
Yes. Only keys must be unique.
Q5. What does put() return?
The previous value for the key, or null if there was none (or the value was null).
Q6. What does add() return in HashSet?
true if the element was added, false if it was already present.
Q7. How many nulls are allowed?
HashSet: one null element. HashMap: one null key and any number of null values.
Q8. Is HashMap a Collection?
No. Map does not extend Collection, though its key set, values and entry set are collections.
Q9. Do they maintain insertion order?
No. Use LinkedHashSet or LinkedHashMap for insertion order.
Q10. Why must hashCode and equals be overridden?
Both structures locate entries by hash code and confirm matches with equals. Inconsistent implementations break uniqueness and lookups.
Q11. Are HashSet and HashMap thread-safe?
No. Use ConcurrentHashMap and ConcurrentHashMap.newKeySet() for concurrent access.
Q12. What is the default capacity and load factor?
Capacity 16 and load factor 0.75 for both; the table doubles when 75% full.
Q13. What happens on hash collisions?
Entries in the same bucket form a linked list, converted to a balanced tree when it grows beyond 8 entries (Java 8+).
Q14. How do I iterate a HashMap?
Use for (Map.Entry<K, V> e : map.entrySet()) or map.forEach((k, v) -> ...).
Q15. Can I get an element from a HashSet?
There is no get; you can only check membership or iterate. Use a map if you need lookup by key.
Q16. How do I count occurrences of words?
Use a HashMap<String, Integer> with map.merge(word, 1, Integer::sum).
Q17. How do I get the keys of a HashMap as a set?
map.keySet() returns a live Set view of the keys.
Q18. Which uses more memory?
They are similar per entry; a HashSet wraps a HashMap and stores a shared dummy value.
Q19. Can a HashSet contain mutable objects?
It can, but changing fields used in hashCode after insertion makes them unfindable. Prefer immutable elements and keys.
Q20. Is this a common interview question?
Yes. Explain the storage model, add vs put, null handling and how HashSet is built on HashMap.