Reputation: 6017
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
Reputation: 75406
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
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