o7planning

Java WeakHashMap Tutorial with Examples

  1. WeakHashMap
  2. Primitive Keys
  3. Object Keys
  4. Why do we need WeakHashMap?

1. WeakHashMap

WeakHashMap is a class similar to HashMap class, which all use hashing technique to store and retrieve data. The difference is that if an object is specified as a key of WeakHashMap, it can be removed from memory by Garbage Collector (GC) if it is no longer being used somewhere else stronger than GC. Once the key is removed by GC, the corresponding mapping is also removed from WeakHashMap.
In common sense, if an object is in use somewhere, it is useful and cannot be removed from memory. However, WeakHashMap is specially designed and is considered weaker than GC, an object whose key can still be removed from memory.
public class WeakHashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>
AnyObject class will participate in the examples in this article:
AnyObject.java
package org.o7planning.beans;

public class AnyObject  {
    private String s;
    public AnyObject(String s)  {
        this.s = s;
    }
    public String getS() {
        return s;
    }
}
First, let's see the example below, then we'll analyze what happened:
WeakHashMap_objectKey_ex1.java
package org.o7planning.weakhashmap.ex;

import java.util.WeakHashMap;

import org.o7planning.beans.AnyObject;

public class WeakHashMap_objectKey_ex1 {

    public static void main(String[] args) throws InterruptedException {
        // (1) Create a reference objK1 points to AnyObject("S1") object.
        AnyObject objK1 = new AnyObject("S1");
        AnyObject objK2 = new AnyObject("S2");

        // Create WeakHashMap object:
        WeakHashMap<AnyObject,Integer> map = new  WeakHashMap<AnyObject,Integer>();
        
        map.put(objK1, 1000);
        map.put(objK2, 2000);
        
        System.out.println(map);
        
        // (2) Set reference objK1 to null.
        objK1 = null;
        
        // Garbage Collector is called
        System.gc();
        System.out.println("\n --- After Garbage Collector is called: --- \n");
        
        Thread.sleep(3000);
        System.out.println(map);
    }
}
Output:
{org.o7planning.beans.AnyObject@1c4af82c=2000, org.o7planning.beans.AnyObject@5e91993f=1000}

 --- After Garbage Collector is called: ---

{org.o7planning.beans.AnyObject@1c4af82c=2000}
(1) - First, objK1 reference is created and pointed to AnyObject("S1") object, which is a key of WeakHashMap.
(2) -ObjK1 reference is pointing to a null value. At this time, there are no longer any strong references that point to AnyObject("S1") object. Although it is being used as a key of WeakHashMap, it is still considered eligible to be removed by Garbage Collector. Since GC is considered stronger than WeakHashMap.
Garbage Collector
Java's Garbage Collector works automatically to remove unused objects from memory. You can actively call it with System.gc() method, but there is no guarantee that it will be effective immediately.
  • Java Garbage Collector
Modifying the above example, if we replace WeakHashMap by HashMap, AnyObject("S1") object will not be removed by Garbage Collector. Because HashMap is considered stronger than Garbage Collector.
HashMap_objectKey_ex1.java
package org.o7planning.weakhashmap.ex;

import java.util.HashMap;

import org.o7planning.beans.AnyObject;

public class HashMap_objectKey_ex1 {

    public static void main(String[] args) throws InterruptedException {
        // (1) Create a reference objK1 points to AnyObject("S1") object.
        AnyObject objK1 = new AnyObject("S1");
        AnyObject objK2 = new AnyObject("S2");

        // Create HashMap object:
        HashMap<AnyObject,Integer> map = new  HashMap<AnyObject,Integer>();
        
        map.put(objK1, 1000);
        map.put(objK2, 2000);
        
        System.out.println(map);
        
        // (2) Set reference objK1 to null.
        objK1 = null;
        
        // Garbage Collector is called
        System.gc();
        System.out.println("\n --- After Garbage Collector is called: --- \n");
        
        Thread.sleep(3000);
        System.out.println(map);
    }
}
Output:
{org.o7planning.beans.AnyObject@1c4af82c=2000, org.o7planning.beans.AnyObject@5e91993f=1000}

 --- After Garbage Collector is called: ---

{org.o7planning.beans.AnyObject@1c4af82c=2000, org.o7planning.beans.AnyObject@5e91993f=1000}
In this article we will discuss the different key types of WeakHashMap and how GC treats them.
No
Key Type
Example
1
Primitive
Integer aKey = 3;
String aKey = "aString";
2
Object
newAnyObject();
newString("aString");
newInteger(3);

2. Primitive Keys

Objects created from primitive values that do not use "new" operator will not be removed by GC if it is being used as a key of a WeakHashMap.
Primitive Keys
Integer key1 = 1000;
Double key2 = 2000.2;
String key3 = "SomeKey";
WeakHashMap_primitiveKey_ex1.java
package org.o7planning.weakhashmap.ex;

import java.util.WeakHashMap;

public class WeakHashMap_primitiveKey_ex1 {

    public static void main(String[] args) throws InterruptedException {
        // (1) Create a reference objK1 points to a primitive value.
        Integer objK1 = 100;
        Integer objK2 = 200;

        // Create WeakHashMap object:
        WeakHashMap<Integer, String> map = new WeakHashMap<Integer, String>();

        map.put(objK1, "One Hundred");
        map.put(objK2, "Two Hundred");

        System.out.println(map);

        // (2) Set reference objK1 to null.
        objK1 = null;

        // Garbage Collector is called
        System.gc();
        System.out.println("\n --- After Garbage Collector is called: --- \n");

        Thread.sleep(5000);
        System.out.println(map);
    }
}
Output:
{200=Two Hundred, 100=One Hundred}

 --- After Garbage Collector is called: ---

{200=Two Hundred, 100=One Hundred}

3. Object Keys

Objects created with "new" operator will be removed from memory by GC if there is no strong reference that point to it, even if it is being used as a key of the WeakHashMap. As mentioned above, GC is considered stronger than WeakHashMap.
Object Keys
AnyObject objK1 = new AnyObject("S1");
String objK2 = new String("S2");
Integer objK3 = new Integer(1000);
String objK4 = new String("S4");
Example:
WeakHashMap_objectKey_ex2.java
package org.o7planning.weakhashmap.ex;

import java.util.WeakHashMap;

import org.o7planning.beans.AnyObject;

public class WeakHashMap_objectKey_ex2 {

    public static void main(String[] args) throws InterruptedException {
        // (1) Create a reference objK1 points to String object.
        AnyObject objK1 = new AnyObject("S1");
        String objK2 = new String("S2");
        Integer objK3 = new Integer(1000);
        String objK4 = new String("S4");

        // Create WeakHashMap object:
        WeakHashMap<Object,Integer> map = new  WeakHashMap<Object,Integer>();
        
        map.put(objK1, 1000);
        map.put(objK2, 2000);
        map.put(objK3, 3000);
        map.put(objK4, 4000);
        
        System.out.println(map);
        
        // (2) Set references objK1, objK2, objK3 to null.
        objK1 = null;
        objK2 = null;
        objK3 = null;
        
        // Garbage Collector is called
        System.gc();
        System.out.println("\n --- After Garbage Collector is called: --- \n");
        
        Thread.sleep(3000);
        System.out.println(map);
    }
}
Output:
{S2=2000, org.o7planning.beans.AnyObject@5e91993f=1000, S4=4000, 1000=3000}

 --- After Garbage Collector is called: ---

{S4=4000}
Objects created by "new" operator will be removed from memory by GC if the program needs more memory and if there are no strong references pointing to it. In this case you do not need to actively call the System.gc() method.
In the example below we try to fill the memory by creating lots of objects continuously.
WeakHashMap_objectKey_ex3.java
package org.o7planning.weakhashmap.ex;

import java.util.WeakHashMap;

import org.o7planning.beans.AnyObject;

public class WeakHashMap_objectKey_ex3 {

    public static void main(String[] args) throws InterruptedException {
        // (1) Create a reference objK1 points to String object.
        AnyObject objK1 = new AnyObject("S1");
        String objK2 = new String("S2");
        Integer objK3 = new Integer(1000);
        String objK4 = new String("S4");
        String objK5 = "S5"; // Primitive Key

        // Create WeakHashMap object:
        WeakHashMap<Object,Integer> map = new  WeakHashMap<Object,Integer>();
        
        map.put(objK1, 1000);
        map.put(objK2, 2000);
        map.put(objK3, 3000);
        map.put(objK4, 4000);
        map.put(objK5, 5000);
        
        int ORIGIN_MAP_SIZE = map.size();
        
        System.out.println(map);  
        
        int i = 0;
        while(true)  {
            if(map.size() < ORIGIN_MAP_SIZE) {
                System.out.println("WeakHashMap Size: " + map.size());
                System.out.println(map);
                break;
            }
            i++;
            // (2) Make the memory full by creating lots of Strings
            String s = new String("String" + i);
            System.out.println("Create new String: " + s);
            System.out.println("   >>> Now WeakHashMap size is: " + map.size());
        }
    }
}
Output:
{S2=2000, org.o7planning.beans.AnyObject@5e91993f=1000, S5=5000, S4=4000, 1000=3000}
Create new String: String1

....

Create new String: String347615
   >>> Now WeakHashMap size is: 5
Create new String: String347616
   >>> Now WeakHashMap size is: 5
Create new String: String347617
   >>> Now WeakHashMap size is: 5
WeakHashMap Size: 1
{S5=5000}

4. Why do we need WeakHashMap?

Basically, WeakHashMap is a solution to save memory, which is useful if you need a Map object to store mappings for the keys you know at a time. Keys that are no longer needed are automatically removed by GC.
Beside though characteristics mentioned above, WeakHashMap has all the characteristics of a regular Map. You can see more how to use Map in the article below:
See more: