Что происходит в Java при добавлении значения по уже существующему ключу в Map?

Ответ

При добавлении пары ключ-значение в Map (например, HashMap) с ключом, который уже присутствует в коллекции, старое значение, ассоциированное с этим ключом, перезаписывается новым значением. Ключ остается прежним. Это фундаментальное свойство Map — каждый ключ может быть связан только с одним значением.

Базовое поведение (перезапись):

Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 10); // Добавляет пару ("Alice", 10)
scores.put("Alice", 25); // Перезаписывает значение. Теперь ("Alice", 25)

System.out.println(scores.get("Alice")); // Вывод: 25
System.out.println(scores.size()); // Вывод: 1 (ключ один)

Методы для "складывания" значений (если это требуется): Если по бизнес-логике нужно не перезаписать, а, например, сложить числовые значения, следует использовать специальные методы:

  1. merge() — Идеален для агрегации:

    Map<String, Integer> totals = new HashMap<>();
    totals.put("budget", 1000);
    
    // Если ключ "budget" существует, сложить старое и новое значение.
    // Если ключа нет, просто положить значение 500.
    totals.merge("budget", 500, Integer::sum); // Теперь "budget" = 1500
    totals.merge("newItem", 300, Integer::sum); // Ключа не было -> "newItem" = 300
  2. compute() — Полный контроль над вычислением нового значения:

    Map<String, List<String>> groups = new HashMap<>();
    
    groups.compute("teamA", (key, currentList) -> {
        if (currentList == null) {
            currentList = new ArrayList<>();
        }
        currentList.add("New Member");
        return currentList;
    });
  3. computeIfAbsent() / computeIfPresent() — Упрощенные версии для частых сценариев.

Важно: Стандартный put() всегда выполняет замену, а не сложение. Для агрегирующих операций необходимо явно использовать merge(), compute() или вручную получать старое значение.

Ответ 18+ 🔞

Ну, слушай, история про Map — это вообще классика, блядь. Представь себе, у тебя есть шкафчик, сука, с ключами. На каждом ключе написано имя, а внутри лежит хуйня какая-то. Ты пришёл, повесил свой ключ "Alice" и положил туда число 10. Всё, порядок.

А потом приходит какой-то мудак, тоже с ключом "Alice", и пытается запихнуть туда своё число 25. И что происходит, блядь? А происходит то, что старый пакет с десяткой выёбывается нахуй, а на его место ложится новая двадцатка с пятёркой. Ключ-то один и тот же, ёпта! Шкафчик не резиновый, чтобы для одного имени два отсека делать. Это фундаментально, как закон тяготения, блядь. Запомни раз и навсегда.

Вот, смотри, как это выглядит в коде, тут всё просто, как три копейки:

Map<String, Integer> scores = new HashMap<>();
scores.put("Alice", 10); // Положил десятку для Алисы
scores.put("Alice", 25); // ААА, БЛЯДЬ! Выкинул десятку, положил двадцать пять!

System.out.println(scores.get("Alice")); // Вывод: 25 (десяточка, прости, сгинула)
System.out.println(scores.size()); // Вывод: 1 (ключ-то один, ёбаный насос!)

Вот и вся магия, сука. Старое значение накрылось медным тазом. Навсегда.

А если мне надо не заменить, а, например, ПРИБАВИТЬ, блядь? Ну, например, ты считаешь бабки, и тебе нужно не последнюю сумму хранить, а общую. Тут стандартный put() — это как топором по яйцам: отрубил и забыл. Не годится.

Для таких хитрожопых случаев есть специальные методы, которые не просто тупо заменяют, а думают, блядь.

  1. merge() — царь и бог агрегации. Сказал "сложи" — он сложит. Сказал "сконкатенируй" — он сконкатенирует. Красота, ёпта!

    Map<String, Integer> totals = new HashMap<>();
    totals.put("budget", 1000); // Бюджет был 1000
    
    // Говорим: "Э, шкафчик, если для 'budget' что-то лежит, прибавь к этому 500.
    // А если нихуя не лежит, то просто положи 500 и не парься".
    totals.merge("budget", 500, Integer::sum); // Теперь "budget" = 1500, ебать!
    totals.merge("newItem", 300, Integer::sum); // Ключа не было -> просто кладём 300
  2. compute() — полный контроль, как в кабине пилота. Хочешь — прибавляй, хочешь — список там формируй, хочешь — нахуй всё удаляй. Делаешь что хочешь.

    Map<String, List<String>> groups = new HashMap<>();
    
    groups.compute("teamA", (key, currentList) -> {
        if (currentList == null) { // Если списка ещё нет, блядь...
            currentList = new ArrayList<>(); // ...создаём пустой!
        }
        currentList.add("New Member"); // Кидаем нового члена команды
        return currentList; // И возвращаем обновлённый список на место
    });
  3. computeIfAbsent() / computeIfPresent() — это такие упрощённые братья compute(). Один работает, только если ключа НЕТ, а второй — только если ключ УЖЕ ЕСТЬ. Для ленивых, но умных.

Итог, блядь, запомни: Обычный put() — это тупой сапёр, который всегда подрывает старую мину. Если тебе надо не взорвать, а аккуратно разрядить и добавить своего тротила — используй merge() или compute(). Всё, вопрос закрыт, в рот меня чих-пых.