에러 발생
java.lang.IllegalStateException: **Duplicate key 'key로 저장하려는 값'** (attempted merging values ~~)
오늘도 만난 에러,,
뜯어봐야 알겠지만 대충 봐도 key 값이 중복되어 발생한 에러다.
에러 원인
에러가 발생한 부분을 찾아보니 아래와 같았다.
Map<String, Member> memberMap = memberInfoRepository.findByMemberIds(memberIds).stream()
.collect(Collectors.toMap(Member::getMemberId, member -> member));
여기서 Collectors.toMap() 호출 시 중복되는 key 값이 존재하는 것이 에러의 원인이었다.
memberId를 key, Member 객체를 value로 넣으려고 하는 상황에서 memberId가 동일한 데이터가 2개가 존재하기 때문이다.
여기서 toMap() 메서드에 대한 설명을 확인해보자.
Returns a Collector that accumulates elements into a Map whose keys and values are the result of applying the provided mapping functions to the input elements. If the mapped keys contain duplicates (according to Object.equals(Object)), an IllegalStateException is thrown when the collection operation is performed. If the mapped keys might have duplicates, use toMap(Function, Function, BinaryOperator) instead.
노란색으로 표시해둔 이 부분을 살펴보면 매핑된 key가 중복되면 IllegalStateException가 발생할 수 있다고 하며, 만약 key가 중복될 가능성이 있는 경우에는 toMap(Function, Function, BinaryOperator)을 대신 사용하길 권장한다.
해결 방법
그럼 위의 설명에 따라 toMap(Function, Function, BinaryOperator)을 사용해 해결을 해보자!
BinaryOperator 인자를 보내면 중복되는 데이터가 존재하는 경우 해당 인자를 이용한다.
Map에 먼저 put한 데이터를 사용하고 싶다면 아래와 같이 수정하면 된다.
Map<String, Member> memberMap = memberInfoRepository.findByMemberIds(memberIds).stream()
.collect(Collectors.toMap(Member::getMemberId, member -> member, ((member, member2) -> member))); // toMap IllegalStateException 방지
반대로 Map에 나중에 put되는 데이터를 저장하고 싶다면 아래와 같이 수정하면 된다.
Map<String, Member> memberMap = memberInfoRepository.findByMemberIds(memberIds).stream()
.collect(Collectors.toMap(Member::getMemberId, member -> member, ((member, member2) -> member2))); // toMap IllegalStateException 방지
동일한 데이터가 존재하는 경우
만약 key와 value가 완전히 일치하는 데이터가 여러 개 존재하는 경우에는 아래와 같이 해결할 수 있다.
List<Member> members = List.of(new Member("meberId11", 20), new Member("meberId11", 20));
Map<String, Member> userMap = users.stream()
.distinct()
.collect(Collectors.toMap(Member::getMemberId, member -> member));
stream의 distinct() 메서드를 이용해 중복을 제거한 뒤, Collectors.toMap을 이용하면 된다.
단, Object.equals()를 활용해 비교하므로 Member 클래스에서는 equals와 hashCode 재정의해야 한다. 그렇지 않으면 객체의 동등성 비교가 제대로 작동하지 않는다.
'Java' 카테고리의 다른 글
[Java/MySQL] Timestamp, LocalDateTime 시간 데이터의 반올림 이슈(feat. Fractional Seconds, LocalTime.MAX) (1) | 2023.11.30 |
---|---|
[Java] Integer ArrayList을 int 배열로 변환하는 방법 (1) | 2023.09.24 |
[Java/DB] ORM이란? MyBatis와 JPA 비교 및 예제 (0) | 2023.08.25 |
[Java] JVM(Java Virtual Machine)이란? (0) | 2023.08.22 |
[Java] 코드 특정 구간의 실행 시간 구하기 (0) | 2023.06.14 |