Как заставить ComputeIfPresent работать с Картой в Карте?

При попытке изменить карту с помощью метода computeIfPresent() у меня возникла проблема с реализацией этого метода, когда я использую innerMap.

Это работает:

Map<String, Integer> mapOne = new HashMap<>();
mapOne.computeIfPresent(key, (k, v) -> v + 1);

Это не работает:

Map<String, Map<String, Integer>> mapTwo = new HashMap<>();
mapTwo.computeIfPresent(key, (k, v) -> v.computeIfPresent(anotherKey, (x, y) -> y + 1);

Во втором примере я получаю следующее сообщение об ошибке: "Неверный тип возврата в выражении лямбда: Integer не может быть преобразован в Map<String, Integer> ". Моя IDE распознает v как карту. Но функция не работает.

По-видимому, метод возвращает Integer, но я не вижу, как это отличается от первого метода без Innermap. До сих пор я не нашел подобного случая в Интернете.

Как я могу заставить это работать?

Ответ 1

Внешнее выражение лямбда должно возвращать Map ссылается v:

mapTwo.computeIfPresent(key, 
                        (k, v) -> {
                                v.computeIfPresent(anotherKey, (x, y) -> y + 1); 
                                return v;
                            });

Он не может вернуть значение Integer выражения v.computeIfPresent(anotherKey, (x, y) → y + 1); ,

Ответ 2

Чтобы понять вашу проблему, давайте взглянем на подпись метода, который вы используете:

V computeIfPresent(K key, BiFunction<? super K,? super V,? extends V> remappingFunction)

Как вы можете видеть, он возвращает тип, основанный на параметре V generic, который обозначает значение, которое хранится в Map. Здесь вы столкнулись с проблемой: ваша внутренняя карта хранит Integer, поэтому, когда вы вызываете computeIfPresent, вы получаете Integer тогда как ваша внешняя карта требует другой Map.

РЕДАКТИРОВАТЬ:
Во время написания я понял, что Эран уже дал пример кода, который показывает, как это сделать.
Но я оставлю этот ответ, потому что он объясняет, почему ваш подход не работает, поэтому он может помочь кому-то.

Ответ 3

Немного не по теме (вроде), но делая то же самое для одной и той же Карты, ломается загадочными способами:

// 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<>();