Как заставить 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<>();