Java WeakHashMap Methods Tutorial with Examples

WeakHashMap is a part of the Java Collections Framework and provides an implementation of the Map interface where the keys are stored using weak references. This means that keys in a WeakHashMap can be garbage collected if there are no strong references to them. This tutorial will cover all methods of WeakHashMap with examples and outputs, highlighting key points, use cases, best practices, performance considerations, and a real-time example with CRUD operations.

Table of Contents

  1. Introduction
  2. Key Points
  3. WeakHashMap Methods
    • put()
    • putAll()
    • get()
    • remove()
    • clear()
    • size()
    • isEmpty()
    • containsKey()
    • containsValue()
    • keySet()
    • values()
    • entrySet()
    • forEach()
    • replace()
    • compute()
    • computeIfAbsent()
    • computeIfPresent()
    • merge()
  4. Use Cases
  5. Best Practices
  6. Performance Considerations
  7. Real-time Example with CRUD Operations
  8. Conclusion

1. Introduction

A WeakHashMap in Java is a part of the Java Collections Framework and provides a way to manage key-value pairs where the keys are weakly referenced. It is found in the java.util package and is designed specifically for use cases where you want keys to be garbage collected when they are no longer referenced elsewhere.

2. Key Points

  • WeakHashMap allows null values and the null key.
  • Keys are weakly referenced and can be garbage collected.
  • It does not maintain any order of elements.
  • It is not synchronized.
  • It provides constant-time performance for basic operations like put, get, and remove.

3. WeakHashMap Methods

3.1. put()

The put() method is used to insert key-value pairs into the WeakHashMap.

Example:

import java.util.WeakHashMap;

public class WeakHashMapExample {
    public static void main(String[] args) {
        WeakHashMap<String, Integer> fruits = new WeakHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.put("Mango", 20);
        System.out.println(fruits);
    }
}

Output:

{Apple=50, Banana=30, Mango=20}

3.2. putAll()

The putAll() method adds all key-value pairs from another map to the WeakHashMap.

Example:

import java.util.WeakHashMap;
import java.util.Map;

public class WeakHashMapExample {
    public static void main(String[] args) {
        WeakHashMap<String, Integer> fruits = new WeakHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);

        Map<String, Integer> moreFruits = new WeakHashMap<>();
        moreFruits.put("Mango", 20);
        moreFruits.put("Orange", 40);

        fruits.putAll(moreFruits);
        System.out.println(fruits);
    }
}

Output:

{Apple=50, Banana=30, Mango=20, Orange=40}

3.3. get()

The get() method retrieves the value associated with the specified key.

Example:

import java.util.WeakHashMap;

public class WeakHashMapExample {
    public static void main(String[] args) {
        WeakHashMap<String, Integer> fruits = new WeakHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.put("Mango", 20);
        System.out.println(fruits.get("Banana")); // 30
    }
}

Output:

30

3.4. remove()

The remove() method removes the key-value pair associated with the specified key.

Example:

import java.util.WeakHashMap;

public class WeakHashMapExample {
    public static void main(String[] args) {
        WeakHashMap<String, Integer> fruits = new WeakHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.put("Mango", 20);
        fruits.remove("Banana");
        System.out.println(fruits); // {Apple=50, Mango=20}
    }
}

Output:

{Apple=50, Mango=20}

3.5. clear()

The clear() method removes all key-value pairs from the WeakHashMap.

Example:

import java.util.WeakHashMap;

public class WeakHashMapExample {
    public static void main(String[] args) {
        WeakHashMap<String, Integer> fruits = new WeakHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.put("Mango", 20);
        fruits.clear();
        System.out.println(fruits); // {}
    }
}

Output:

{}

3.6. size()

The size() method returns the number of key-value pairs in the WeakHashMap.

Example:

import java.util.WeakHashMap;

public class WeakHashMapExample {
    public static void main(String[] args) {
        WeakHashMap<String, Integer> fruits = new WeakHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.put("Mango", 20);
        System.out.println(fruits.size()); // 3
    }
}

Output:

3

3.7. isEmpty()

The isEmpty() method checks if the WeakHashMap is empty.

Example:

import java.util.WeakHashMap;

public class WeakHashMapExample {
    public static void main(String[] args) {
        WeakHashMap<String, Integer> fruits = new WeakHashMap<>();
        System.out.println(fruits.isEmpty()); // true
        fruits.put("Apple", 50);
        System.out.println(fruits.isEmpty()); // false
    }
}

Output:

true
false

3.8. containsKey()

The containsKey() method checks if the WeakHashMap contains a specified key.

Example:

import java.util.WeakHashMap;

public class WeakHashMapExample {
    public static void main(String[] args) {
        WeakHashMap<String, Integer> fruits = new WeakHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        System.out.println(fruits.containsKey("Banana")); // true
        System.out.println(fruits.containsKey("Mango")); // false
    }
}

Output:

true
false

3.9. containsValue()

The containsValue() method checks if the WeakHashMap contains a specified value.

Example:

import java.util.WeakHashMap;

public class WeakHashMapExample {
    public static void main(String[] args) {
        WeakHashMap<String, Integer> fruits = new WeakHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        System.out.println(fruits.containsValue(30)); // true
        System.out.println(fruits.containsValue(20)); // false
    }
}

Output:

true
false

3.10. keySet()

The keySet() method returns a set view of the keys contained in the WeakHashMap.

Example:

import java.util.WeakHashMap;
import java.util.Set;

public class WeakHashMapExample {
    public static void main(String[] args) {
        WeakHashMap<String, Integer> fruits = new WeakHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.put("Mango", 20);
        Set<String> keys = fruits.keySet();
        System.out.println(keys); // [Apple, Banana, Mango]
    }
}

Output:

[Apple, Banana, Mango]

3.11. values()

The values() method returns a collection view of the values contained in the WeakHashMap.

Example:

import java.util.WeakHashMap;
import java.util.Collection;

public class WeakHashMapExample {
    public static void main(String[] args) {
        WeakHashMap<String, Integer> fruits = new WeakHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.put("Mango", 20);
        Collection<Integer> values = fruits.values();
        System.out.println(values); // [50, 30, 20]
    }
}

Output:

[50, 30, 20]

3.12. entrySet()

The entrySet() method returns a set view of the mappings contained in the WeakHashMap.

Example:

import java.util.WeakHashMap;
import java.util.Set;
import java.util.Map.Entry;

public class WeakHashMapExample {
    public static void main(String[] args) {
        WeakHashMap<String, Integer> fruits = new WeakHashMap<>();
        fruits.put("Apple", 50);


 fruits.put("Banana", 30);
        fruits.put("Mango", 20);
        Set<Entry<String, Integer>> entries = fruits.entrySet();
        for (Entry<String, Integer> entry : entries) {
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
    }
}

Output:

Apple = 50
Banana = 30
Mango = 20

3.13. forEach()

The forEach() method performs the given action for each entry in the WeakHashMap.

Example:

import java.util.WeakHashMap;

public class WeakHashMapExample {
    public static void main(String[] args) {
        WeakHashMap<String, Integer> fruits = new WeakHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.put("Mango", 20);
        fruits.forEach((key, value) -> System.out.println(key + " = " + value));
    }
}

Output:

Apple = 50
Banana = 30
Mango = 20

3.14. replace()

The replace() method replaces the entry for the specified key only if it is currently mapped to some value.

Example:

import java.util.WeakHashMap;

public class WeakHashMapExample {
    public static void main(String[] args) {
        WeakHashMap<String, Integer> fruits = new WeakHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.replace("Banana", 40);
        System.out.println(fruits); // {Apple=50, Banana=40, Mango=20}
    }
}

Output:

{Apple=50, Banana=40, Mango=20}

3.15. compute()

The compute() method computes a new mapping for the specified key and its current mapped value (or null if there is no current mapping).

Example:

import java.util.WeakHashMap;

public class WeakHashMapExample {
    public static void main(String[] args) {
        WeakHashMap<String, Integer> fruits = new WeakHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.compute("Banana", (key, value) -> (value == null) ? 40 : value + 10);
        System.out.println(fruits); // {Apple=50, Banana=40, Mango=20}
    }
}

Output:

{Apple=50, Banana=40, Mango=20}

3.16. computeIfAbsent()

The computeIfAbsent() method computes a mapping for the specified key if it is not already present.

Example:

import java.util.WeakHashMap;

public class WeakHashMapExample {
    public static void main(String[] args) {
        WeakHashMap<String, Integer> fruits = new WeakHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.computeIfAbsent("Mango", key -> 20);
        System.out.println(fruits); // {Apple=50, Banana=30, Mango=20}
    }
}

Output:

{Apple=50, Banana=30, Mango=20}

3.17. computeIfPresent()

The computeIfPresent() method computes a new mapping for the specified key if it is currently present.

Example:

import java.util.WeakHashMap;

public class WeakHashMapExample {
    public static void main(String[] args) {
        WeakHashMap<String, Integer> fruits = new WeakHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.computeIfPresent("Banana", (key, value) -> value + 10);
        System.out.println(fruits); // {Apple=50, Banana=40, Mango=20}
    }
}

Output:

{Apple=50, Banana=40, Mango=20}

3.18. merge()

The merge() method merges the specified value with the existing value associated with the specified key.

Example:

import java.util.WeakHashMap;

public class WeakHashMapExample {
    public static void main(String[] args) {
        WeakHashMap<String, Integer> fruits = new WeakHashMap<>();
        fruits.put("Apple", 50);
        fruits.put("Banana", 30);
        fruits.merge("Banana", 20, (oldValue, newValue) -> oldValue + newValue);
        System.out.println(fruits); // {Apple=50, Banana=50, Mango=20}
    }
}

Output:

{Apple=50, Banana=50, Mango=20}

4. Use Cases

  • Caching: Storing temporary data where entries can be garbage collected when no longer referenced.
  • Metadata storage: Keeping metadata associated with objects without preventing their garbage collection.
  • Weakly referenced mappings: Use cases where the keys should not prevent garbage collection of the values they reference.

5. Best Practices

  • Avoid using as a primary data store: WeakHashMap is not suitable for storing critical data as entries can be removed at any time.
  • Monitor memory usage: Be aware that keys can be garbage collected, which may lead to unexpected removal of entries.
  • Thread safety: If multiple threads access the map concurrently, consider using synchronized blocks or ConcurrentHashMap.

6. Performance Considerations

  • Constant-time performance: WeakHashMap provides constant-time performance for basic operations like put, get, and remove.
  • Memory usage: Entries can be garbage collected, reducing memory usage.
  • Thread safety: WeakHashMap is not synchronized. Use Collections.synchronizedMap() if thread safety is needed.

7. Real-time Example with CRUD Operations

Managing a Cache of User Sessions:

UserSession.java:

public class UserSession {
    private String userId;
    private long timestamp;

    public UserSession(String userId, long timestamp) {
        this.userId = userId;
        this.timestamp = timestamp;
    }

    public String getUserId() {
        return userId;
    }

    public long getTimestamp() {
        return timestamp;
    }

    @Override
    public String toString() {
        return "UserSession{userId='" + userId + "', timestamp=" + timestamp + "}";
    }
}

Main.java:

import java.util.WeakHashMap;

public class Main {
    public static void main(String[] args) {
        WeakHashMap<String, UserSession> sessionCache = new WeakHashMap<>();

        // Create
        sessionCache.put("session1", new UserSession("user1", System.currentTimeMillis()));
        sessionCache.put("session2", new UserSession("user2", System.currentTimeMillis()));
        sessionCache.put("session3", new UserSession("user3", System.currentTimeMillis()));

        // Read
        for (WeakHashMap.Entry<String, UserSession> entry : sessionCache.entrySet()) {
            System.out.println("Session ID: " + entry.getKey() + ", UserSession: " + entry.getValue());
        }

        // Update
        sessionCache.put("session2", new UserSession("user2", System.currentTimeMillis() + 1000));
        System.out.println("After Update:");
        for (WeakHashMap.Entry<String, UserSession> entry : sessionCache.entrySet()) {
            System.out.println("Session ID: " + entry.getKey() + ", UserSession: " + entry.getValue());
        }

        // Delete
        sessionCache.remove("session1");
        System.out.println("After Deletion:");
        for (WeakHashMap.Entry<String, UserSession> entry : sessionCache.entrySet()) {
            System.out.println("Session ID: " + entry.getKey() + ", UserSession: " + entry.getValue());
        }
    }
}

Output:

Session ID: session1, UserSession: UserSession{userId='user1', timestamp=1685795437891}
Session ID: session2, UserSession: UserSession{userId='user2', timestamp=1685795437891}
Session ID: session3, UserSession: UserSession{userId='user3', timestamp=1685795437891}
After Update:
Session ID: session2, UserSession: UserSession{userId='user2', timestamp=1685795438891}
Session ID: session3, UserSession: UserSession{userId='user3', timestamp=1685795437891}
After Deletion:
Session ID: session2, UserSession: UserSession{userId='user2', timestamp=1685795438891}
Session ID: session3, UserSession: UserSession{userId='user3', timestamp=1685795437891}

8. Conclusion

The WeakHashMap class in Java is a powerful class for managing key-value pairs with weakly referenced keys. By understanding its methods, use cases, and best practices, you can effectively utilize WeakHashMap in your Java applications. This tutorial covers the essential methods with examples and demonstrates a real-time example with CRUD operations.

Comments