🧠 Как в Java сломать equals() и потерять данные в HashMap



Сегодня покажу, как неочевидный баг в equals()/hashCode() может привести к потере данных при работе с HashMap.

Допустим, у вас есть Entity:

public class User {
private String id;
private String name;

// equals/hashCode только по id
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof User)) return false;
User user = (User) o;
return Objects.equals(id, user.id);
}

@Override
public int hashCode() {
return Objects.hash(id);
}
}


Вроде норм. Но теперь добавим такого юзера в HashMap, а потом... изменим его id:

User user = new User();
user.setId("1");
user.setName("Alice");

Map<User, String> map = new HashMap<>();
map.put(user, "value");

user.setId("2"); // ⚠️ ключ стал "невидимым"

System.out.println(map.get(user)); // null 😱


📌 Почему так происходит?

HashMap ищет ключ по hashCode() → ищет бакет → сравнивает через equals(). А hashCode() уже другой, и объект "теряется".

💡 Совет: если вы используете объект как ключ в мапе или добавляете его в Set, не изменяйте его поля, участвующие в equals()/hashCode()!

📌 А как правильно?

- Делайте такие поля final;
- Или используйте неизменяемые типы (record);
- Или не используйте такие объекты как ключи вовсе.

Вот безопасный вариант с record:

public record User(String id, String name) {}

👉 @BookJava
Просмотры: 558
Открыть в MAX Сообщить о неточности

Репосты публикации

Публикация канала

Сообщить о неточности

Опишите, что нужно исправить. Если есть источник, добавьте ссылку.

Вы покидаете datool.ru

Ссылка ведёт на внешний сайт. datool.ru не отвечает за его содержимое — проверьте адрес, прежде чем вводить пароли или платёжные данные.

Переход через 10 с

Перейти