Java HashMap

Fast key-value storage with hash-based implementation

๐Ÿƒ What is HashMap?

HashMap is Java's most popular Map implementation that uses hashing for super-fast key-value storage. It provides constant-time performance for basic operations like get and put.


// Simple HashMap example
HashMap<String, Integer> ages = new HashMap<>();
ages.put("Alice", 25);
ages.put("Bob", 30);
System.out.println(ages.get("Alice")); // 25 - Very fast!
                                    

HashMap Key Features

โšก

Super Fast

O(1) average time for get/put operations

HashMap<String, String> cache = new HashMap<>();
cache.put("user123", "John Doe");
String user = cache.get("user123"); // Instant!
๐Ÿ”€

No Order

Elements are not stored in any order

HashMap<String, Integer> map = new HashMap<>();
map.put("C", 3);
map.put("A", 1);
map.put("B", 2);
// Order may be: {B=2, A=1, C=3}
๐Ÿ”„

Null Values

Allows one null key and multiple null values

HashMap<String, String> map = new HashMap<>();
map.put(null, "null key value");
map.put("key1", null);
map.put("key2", null); // Multiple nulls OK
๐Ÿงต

Not Thread-Safe

Use ConcurrentHashMap for threading

// For single-threaded use
HashMap<String, Integer> map = new HashMap<>();

// For multi-threaded use
ConcurrentHashMap<String, Integer> safeMap = 
    new ConcurrentHashMap<>();

๐Ÿ”น Creating and Using HashMap

Basic HashMap operations with examples:

import java.util.*;

public class HashMapExample {
    public static void main(String[] args) {
        // Create HashMap
        HashMap<String, Double> productPrices = new HashMap<>();
        
        // Add items
        productPrices.put("Laptop", 999.99);
        productPrices.put("Mouse", 25.50);
        productPrices.put("Keyboard", 75.00);
        productPrices.put("Monitor", 299.99);
        
        // Get item price
        double laptopPrice = productPrices.get("Laptop");
        System.out.println("Laptop costs: $" + laptopPrice);
        
        // Check if item exists
        if (productPrices.containsKey("Mouse")) {
            System.out.println("Mouse is available");
        }
        
        // Update price
        productPrices.put("Mouse", 22.99); // Price reduced!
        
        // Get with default value
        double webcamPrice = productPrices.getOrDefault("Webcam", 0.0);
        System.out.println("Webcam price: $" + webcamPrice);
        
        // Display all products
        System.out.println("\nAll products:");
        for (Map.Entry<String, Double> entry : productPrices.entrySet()) {
            System.out.println(entry.getKey() + ": $" + entry.getValue());
        }
    }
}

Output:

Laptop costs: $999.99

Mouse is available

Webcam price: $0.0


All products:

Laptop: $999.99

Mouse: $22.99

Keyboard: $75.0

Monitor: $299.99

๐Ÿ”น HashMap with Custom Objects

Using HashMap with custom objects as keys:

class Person {
    String name;
    int age;
    
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // IMPORTANT: Override equals and hashCode for HashMap keys
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person person = (Person) obj;
        return age == person.age && Objects.equals(name, person.name);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    
    @Override
    public String toString() {
        return name + "(" + age + ")";
    }
}

// Usage
HashMap<Person, String> personJobs = new HashMap<>();
Person alice = new Person("Alice", 25);
Person bob = new Person("Bob", 30);

personJobs.put(alice, "Software Engineer");
personJobs.put(bob, "Data Scientist");

System.out.println(alice + " works as: " + personJobs.get(alice));
System.out.println("All employees: " + personJobs);

Output:

Alice(25) works as: Software Engineer

All employees: {Alice(25)=Software Engineer, Bob(30)=Data Scientist}

๐Ÿ”น HashMap Performance Tips

Best practices for optimal HashMap performance:

// 1. Set initial capacity if you know the size
HashMap<String, Integer> largeMap = new HashMap<>(1000);

// 2. Use proper load factor (default 0.75 is usually good)
HashMap<String, Integer> customMap = new HashMap<>(16, 0.75f);

// 3. Good hash code distribution is crucial
class GoodKey {
    private String id;
    private int number;
    
    @Override
    public int hashCode() {
        return Objects.hash(id, number); // Good distribution
    }
}

// 4. Avoid mutable keys
final class ImmutableKey {
    private final String value;
    
    ImmutableKey(String value) {
        this.value = value;
    }
    
    // equals and hashCode methods...
}

// 5. Use putIfAbsent for conditional insertion
HashMap<String, List<String>> groups = new HashMap<>();
groups.putIfAbsent("admins", new ArrayList<>());
groups.get("admins").add("Alice");

// 6. Use compute methods for complex updates
HashMap<String, Integer> wordCount = new HashMap<>();
String[] words = {"hello", "world", "hello", "java"};

for (String word : words) {
    wordCount.compute(word, (key, val) -> (val == null) ? 1 : val + 1);
}
System.out.println("Word counts: " + wordCount);

Output:

Word counts: {java=1, world=1, hello=2}

๐Ÿง  Test Your Knowledge

What is the average time complexity for HashMap get() operation?