4

The traditional code works well like below:

Map<Integer, List<Integer>> map = new HashMap<>();
if (!map.containsKey(1)) {
   map.put(1, new ArrayList<>());
}
map.get(1).add(2);

Now I'd like to try the magic of getOrDefault:

map.getOrDefault(1, new ArrayList<>()).add(2);

But if I use the above line, then map.get(1) is null.

Why?

Sweeper
  • 213,210
  • 22
  • 193
  • 313
LookIntoEast
  • 8,048
  • 18
  • 64
  • 92

2 Answers2

12

Because getOrDefault, as its name suggests, only gets stuff from the map. It doesn't adds a new KVP to the map. When the key is not present, the default value you pass to getOrDefault is returned, but not added to the map, so you'd be adding 2 to an array list that is thrown away immediately.

In other words, this is what your getOrDefault code is doing:

ArrayList<Integer> value;
if (!map.containsKey(1)) {
    value = new ArrayList<>();
} else {
    value = map.get(1);
}
value.add(2);

You should use computeIfAbsent instead. This method actually adds the return value from the function to the map if the key is not present:

map.computeIfAbsent(1, x -> new ArrayList<>()).add(2);
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • imo very bad implementation of a good idea: computeIfAbsent does the thing the author wants, but we don't compute a thing when we add a new ArrayList, so the method is doing the things not related to how it's called and it creates confusing code. I prefer to use the tradition version instead, because it does exactly what it looks like it should do. – Shpytyack Artem Sep 25 '22 at 11:42
1

or you could do:

if(!map.contansKey(1)) map.put(1, new ArrayList<>());
map.get(1).add(2);

so you can save those lines ;)