ConcurrentHashMap putIfAbsent() is returning null

15,138

Solution 1

ConcurrentMap.putIfAbsent returns the previous value associated with the specified key, or null if there was no mapping for the key. You did not have a value associated with "key 3". All correct.

NOTE: Not just for ConcurrentMap, this applies to all implementations of Map.

Solution 2

Problem is that by definition putIfAbsent return old value and not new value (old value for absent is always null). Use computeIfAbsent - this will return new value for you.

private static String get(final String key) {
    return map.computeIfAbsent(key, s -> "value 3");
}

Solution 3

putIfAbsent() returns the previous value associated with the specified key, or null if there was no mapping for the key, and because key 3 is not present in the map so it returns null.

You have added key 1 and key 2 in the map but key 3 is not associated with any value. So you get a null. Map key 3 with some value and putIfAbsent() will return previous value associated with that key.

Like if map already contained key 3 associated with value A

key 3 ---> A

Then on calling map.putIfAbsent("key 3","B") will return A

Solution 4

This is a frequently asked question, which perhaps suggest this behaviour is unintuitive. Maybe the confusion comes from the way dict.setdefault() works in python and other languages. Returning the same object you just put helps cut a few lines of code.

Consider:

if (map.contains(value)){
    obj = map.get(key);
}
else{
    obj = new Object();
}

versus:

obj = map.putIfAbsent(key, new Object());

Solution 5

It's in the javadoc:

returns the previous value associated with the specified key, or null if there was no mapping for the key

Share:
15,138

Related videos on Youtube

Niranjan
Author by

Niranjan

Java programmer

Updated on October 18, 2022

Comments

  • Niranjan
    Niranjan over 1 year

    The following program is printing null. I am not able to understand why.

    public class ConcurrentHashMapTest {
        public static final ConcurrentMap<String, String> map = new ConcurrentHashMap<>(5, 0.9f, 2);
    
        public static void main(String[] args) {
            map.putIfAbsent("key 1", "value 1");
            map.putIfAbsent("key 2", "value 2");
    
            String value = get("key 3");
            System.out.println("value for key 3 --> " + value);
        }
    
        private static String get(final String key) {
            return map.putIfAbsent(key, "value 3");
        }
    }
    

    Could someone help me understand the behavior?

    • Jon Skeet
      Jon Skeet about 10 years
      What behaviour did you expect, and why?
  • Mark Rotteveel
    Mark Rotteveel about 10 years
    For quotes you should use >, not the code formatting.
  • Bozho
    Bozho about 10 years
    Yeah, I forgot... :) haven't answered for a awhile
  • Jerry Chin
    Jerry Chin over 5 years
    it doesn't allow exception throwing, too bad.
  • Ondřej Stašek
    Ondřej Stašek over 5 years
    As any other lambda. So either use @SneakyThrows or rethrow exception as RuntimeException.
  • nurettin
    nurettin over 5 years
    Is this an atomic operation? As in, can the map change between contains and get?
  • Frans
    Frans almost 4 years
    @SneakyThrows is evil.
  • Ondřej Stašek
    Ondřej Stašek almost 4 years
    checked exceptions are far more evil than @SneakyThrows :)