65.9K
CodeProject is changing. Read more.
Home

Java HashMap computeIfAbsent() - How to Use?

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1 vote)

Jan 16, 2023

CPOL

2 min read

viewsIcon

6878

HashMap computeIfAbsent() in Java 8

Overview

The computeIfAbsent method is introduced to the HashMap data structure from Java 8 version.

The syntax of this method is as follows:

public V computeIfAbsent(K key, Function mappingFunction)
  • Here, key represents the key in the Hash map.
  • mappingFunction is a function that computes the value. Remember that mapping function is only called when the value mapped to the key does not exist or it is null.

How Does computeIfAbsent() Work?

  • If the given key is not already mapped to a value (or is mapped to null), the mappingFunction is invoked to compute the value and enters into the map if it is not null.
  • If the mappingFunction returns null, the map will not be updated.
  • If the mappingFunction throws a runtime exception, the exception is rethrown, and this map will not be updated for the provided key.
  • The mappingFunction should not modify this map during computation.
  • Throws ConcurrentModifiedException if it is detected that the mapping function modified this map.

When Should We Use computeIfAbsent()?

  • Most common usage is to insert a key/value pair into the HashMap where value is always a new object initially.

    ex: instead of:

    Map<String, Foo> fooMap = new HashMap<>();
    if(fooMap.get("foo") == null) {
            fooMap.put("foo", new Foo());
    } else {
            // update foo
    }

    we can use computeIfAbsent() as below and avoid the if/else checks.

      Map<String, Foo> fooMap = new
        HashMap<>();fooMap.computeIfAbsent("foo",  k -> new Foo());
        // update foo
  • To implement multi-value map, Map<K, Collection<V>>, i.e., having multiple values per key.

    ex: Instead of:

        Map<String, List<Foo>> fooListMap = new HashMap<>();
        if(fooListMap.get("foo") == null) {
            fooListMap.put("foo", new ArrayList<Foo>());
        } 
        fooListMap.get("foo").add(new Foo());</code>

    we can use computeIfAbsent() as below and write in a single statement.

    Map<String, List<Foo>> fooListMap = new HashMap<>();
    fooListMap.computeIfAbsent("foo", k -> new ArrayList<Foo>()).add(new Foo());

Further Examples

Using computeIfAbsent() When the Value is Null

When the key is not mapped to value or the mapped value is null, then the computeIfAbsent() method invokes the mapping function to derive the value. Remember, if the mapping function returns a null, then the map will not be updated.

  Map<String, String> stringMap = new HashMap<>();
  System.out.println(stringMap.get("TheBackendPro")); // prints null
  stringMap.computeIfAbsent("TheBackendPro", k -> {
     return "https://www.thebackendpro.com/";
  });

  System.out.println(stringMap.get("TheBackendPro")); // prints 
                                                      // https://www.thebackendpro.com/

Using computeIfAbsent() when the Key is Already Mapped to Non-null Value

If the key is already associated with a non-null value, the computeIfAbsent() doesn't invoke the mapping function as the value is already present.

  Map<String, String> stringMap = new HashMap<>();
  stringMap.put("TheBackendPro", "https://www.thebackendpro.com/");
  stringMap.computeIfAbsent("TheBackendPro", k -> {
     return "https://www.google.com/";
  });
  System.out.println(stringMap.get("TheBackendPro")); // prints 
                                     https://www.thebackendpro.com/

Mapping Function Throws a Runtime Exception

When the mapping function throws a runtime exception, the same is propagated to the caller and no mapping is recorded for the key.

  Map<String, String> stringMap = new HashMap<>();
  stringMap.computeIfAbsent("TheBackendPro", k -> {
     throw new RuntimeException("unexpected exception occurred");
  });

Output

  Exception in thread "main" java.lang.RuntimeException: unexpected exception occurred
	at main.java.ComputeIfAbsentTest.lambda$main$2(ComputeIfAbsentTest.java:26)
	at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1134)
	at main.java.ComputeIfAbsentTest.main(ComputeIfAbsentTest.java:25)