Harshal Parekh
Harshal Parekh

Reputation: 6017

Is .put() in .getOrDefault() computed every time?

Map<String, Ob> map = new HashMap<>();
String[] arr = {"a", "a", "c", "c"};

int count = 1;
for (String a: arr) {
    System.out.println("putting \"" + a + "\" in map");
    System.out.println(map.getOrDefault(a, map.put(a, new Ob(a + "" + count++))));
    System.out.println("map: " + map);
}

Ob is a very simple class:

class Ob {
    String o;
    Ob (String message) { o = message; }

    @Override
    public String toString() { return o; }
}

Prints:

putting "a" in map
a1
map: {a=a1}
putting "a" in map
a2                        
map: {a=a2}                     -> Why is the value replaced?
putting "c" in map
c3
map: {a=a2, c=c3}
putting "c" in map
c4
map: {a=a2, c=c4}               -> Why is the value replaced?

I was thinking for the second a it would simply fetch the value a1 and return because a already exists in the map. But it created the object in .put().

It looks like the default in getOrDefault computed even if key exists. How can I write this concisely without creating new objects when the key already exists?

I can write it with an if/else, surely, but I want to see if the current approach can be fixed.

Upvotes: 1

Views: 641

Answers (2)

Yes.

It must be in order to create the value actually passed in to be returned as default value if the value is not present.

You may want to rethink your logic.

Upvotes: 1

David Conrad
David Conrad

Reputation: 16379

The parameter to getOrDefault is evaluated before the method is called (as is always the case with expressions used as method parameters), so it has to happen every time.

Map has a method computeIfAbsent that does what you want, here:

map.computeIfAbsent(a, k -> new Ob(k + "" + count++));

If a is in the map, its value will be returned. If it isn't, it will be passed to the lambda (as parameter k, here) and the value of the lambda will be inserted into the map under key a and also returned.

Upvotes: 3

Related Questions