Reputation: 159
When trying to alter a Map using the computeIfPresent() method I have trouble implementing this method when I use an innerMap.
This works:
Map<String, Integer> mapOne = new HashMap<>();
mapOne.computeIfPresent(key, (k, v) -> v + 1);
This doesn't work:
Map<String, Map<String, Integer>> mapTwo = new HashMap<>();
mapTwo.computeIfPresent(key, (k, v) -> v.computeIfPresent(anotherKey, (x, y) -> y + 1);
In the second example I get the following error message: "Bad return type in lambda expression: Integer cannot be converted to Map<String, Integer>
".
My IDE recognizes v as a Map. But the function doesn't work.
Apparently the method returns an Integer, but I fail to see how this differs from the first method with no Innermap. So far I haven't found a similar case online.
How can I get this to work?
Upvotes: 16
Views: 7127
Reputation: 120968
Slightly off-topic (sort of), but doing the same thing for the same Map, breaks in mysterious ways:
// breaks with ConcurrentModificationException
Map<String, Integer> test = new HashMap<>(); // or = new Hashtable<>();
test.computeIfAbsent("one", x -> test.computeIfAbsent("one", y -> 1));
// IllegalStateException: Recursive update
Map<String, Integer> test = new ConcurrentHashMap<>();
// ... same code
// the only one that works correctly that I am aware of
Map<String, Integer> test = new ConcurrentSkipListMap<>();
Upvotes: 0
Reputation: 2821
In order to understand your problem lets take a look at the signature of the method you are using:
V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)
As you can see, it returns a type based on the V
generic parameter which stands for a value that is stored in Map
. This is where you face the problem: your inner map stores Integer
, so when you call computeIfPresent
, you get Integer
while your outer map requires another Map
.
EDIT:
While writing, I realized that Eran gave a code example already which shows how to do it.
But I will leave this answer since it explains why your approach doesn't work, so it might help someone.
Upvotes: 9
Reputation: 393936
The outer lambda expression should return the Map
referenced by v
:
mapTwo.computeIfPresent(key,
(k, v) -> {
v.computeIfPresent(anotherKey, (x, y) -> y + 1);
return v;
});
It cannot return the Integer
value of the expression v.computeIfPresent(anotherKey, (x, y) -> y + 1);
.
Upvotes: 11