자바에서 개발하다 보면 HashMap이나 HashSet 같은 컬렉션을 활용할 때 사용자 정의 객체를 키로 사용하는 경우가 빈번하게 발생하곤 해요. 그런데 분명히 내용이 똑같은 데이터를 넣었는데도 불구하고 원하는 값을 찾지 못하거나, 중복된 데이터가 저장되는 현상을 마주하면 당황스러울 수 있거든요. 이런 문제는 대부분 해당 객체가 equals와 hashCode 메서드를 제대로 구현하지 않았을 때 발생하는데요. 자바의 HashMap은 내부적으로 해시 테이블 구조를 사용하기 때문에 데이터를 저장할 때 먼저 hash_code()를 호출하여 어느 버킷에 넣을지 결정하고, 그 다음에 equals()를 통해 실제 값이 같은지 확인하는 과정을 거치기 때문이에요.
public record UserKey(
String id,
String name
) {}
// 또는 기존 클래스 방식
public class UserKey {
private final String id;
private final String name;
public UserKey(String id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserKey userKey = (UserKey) o;
return java.util.Objects.equals(id, userKey.id) &&
java.util.Objects.equals(name, userKey.name);
}
@Override
public int hashCode() {
return java.util.Objects.hash(id, name);
}
}
만약 equals를 구현하지 않거나 하나라도 제대로 처리되지 않으면 자바는 기본적으로 객체의 메모리 주소값을 기준으로 비교하게 돼요. 그래서 내용이 같더라도 서로 다른 인스턴스라면 다른 키로 인식해버리는 문제가 생기는 거고요. 특히 실무에서 DTO나 엔티티를 기반으로 데이터를 매핑할 때 이런 실수를 하면 디버깅하기 까다로운 버그가 될 수 있어요. 이 문제를 방지하려면 반드시 두 메서드를 세트로 구현해야 하며, 최근 자바 버전에서는 Record 타입을 활용하면 개발자가 직접 코드를 작성하지 않아도 이 두 메서드가 자동으로 생성되어 안전하게 사용할 수 있거든요. 또한 Lombok 라이브러리를 사용 중이라면 @EqualsAndHashCode 어노테이션을 통해 이를 간편하게 해결할 수도 있어요. 결과적으로 데이터의 일관성을 보장하기 위해 컬렉션의 키로 사용하는 객체는 반드시 적절한 해시 알고리즘과 동등성 비교 로직을 갖추고 있어야 해요.
'develop > Java' 카테고리의 다른 글
| Collectors.toMap 중복 키 예외 처리 및 병합 전략 (0) | 2026.07.27 |
|---|---|
| 자바 버전 히스토리와 LTS 선택 가이드 (0) | 2026.07.20 |
| Java Optional 올바른 사용법 (orElse와 orElseGet 차이) (0) | 2026.07.17 |
| 자바 멀티스레드 환경에서의 ConcurrentHashMap 활용법 (0) | 2026.07.14 |
| Java ConcurrentModificationException 원인과 해결 (Iterator.remove, removeIf) (0) | 2026.07.12 |