[JAVA] List removeAll 값 삭제 안되는 문제해결

yeonjoo913·2023년 7월 24일

JAVA

목록 보기
7/19

프로젝트 개발 중 기본을 다시 생각하게 되는 이슈를 만나 이렇게 정리하게되었다.

문제

2개의 List 값을 비교하고 동일한 값이 있을 경우 removeAll 메소드를 사용하여 값을 삭제하려고 하였다.
첫번째 List의 경우 Redis cache에서 가져온 값이고 두번째 List의 경우 RDB에서 조회해온 값으로, 두 객체의 값은 동일하였지만 삭제가 되지 않는 이슈가 발생하였다.

원인

주소값이 달라 서로 다른 객체로 판단했기 때문이다.
removeAll의 경우 요소들을 contains메소드로 체크하는데 contains는 Objects.equals로 요소의 포함 여부를 체크한다. equals method는 주소 값이 다른 객체는 서로 다른 객체로 판단하기 때문에 삭제가 이루어 지지 않은 것이었다.

해결 방안

@EqualsAndHashCode 사용

  • callSuper = false 자신 클래스의 필드 값만 적용
  • callSuper = true 자신 클래스 뿐만 아니라, 부모 클래스 필드 값도 체크
  • of - 해당 필드만 체크
  • exclude - 해당 필드를 제외하고 체크

=> of 옵션을 사용하여 id 필드를 명시하여 사용하였다.

권장하는 방법

  • 항상 @EqualsAndHashCode(of={”변수명”}) 형태로 동등성 비교에 필요한 필드를 명시하는 것이 좋다.
  • 실무에서는 실수하기 마련이니, 차라리 IDE 자동생성으로 꼭 필요한 필드를 지정하는 것이 나을 수도 있다고 한다.

위에 이슈를 해결하면서 공부한 equalsa와 hashCode에 대해 다시 정리해보려고 한다.

equals - equality(동등성)

  • 두 객체의 내용이 같은지
  • 객체의 동일성(주소가 같음)이 아닌 논리적 동일성(구성하는 값이 같음)일 경우, 재정의 해서 사용해라
  • @Override로 재정의 하지 않으면 그 class의 instance는 오직 자기 자신 과만 같게 된다.
  • 양질의 equals method 구현 방법
    • == 연산자를 사용해 입력이 자기 자신의 참조인지 확인한다.
    • 핵심 필드들이 모두 일치하는지 검사한다.
    • equals를 재정의 할 때 hashCode도 반드시 재정의 한다.

hashcode - identity(동일성)

  • 두 객체가 같은 객체인지
  • equals 비교에 사용되는 정보가 변경되지 않았다면, 애플리케이션이 실행되는 동안 객체의 hashCode 메서드는 몇 번을 호출해도 항상 같은 값을 반환한다. (단, 애플리케이션을 다시 실행하면 값은 바뀔 수 있다.)
  • equals(Object)가 두 객체를 같다고 판단했으면, 두 객체의 hashCode 값은 항상 같다.
  • 하지만 equals(Object)가 두 객체를 다르다고 판단했더라도, 두 객체의 hashCode 값은 같을 수 있다. (해시 충돌)

equals()와 hashcode()를 같이 재정의해야한다. 왜??

만약 equals()와 hashcode() 중 하나만 재정의 하면 어떻게 될까? 위 예에서도 봤듯이 hashcode()를 재정의 하지 않으면 같은 값 객체라도 해시값이 다를 수 있다. 따라서 HashTable에서 해당 객체가 저장된 버킷을 찾을 수 없다.

반대로 equals()를 재정의하지 않으면 hashcode()가 만든 해시값을 이용해 객체가 저장된 버킷을 찾을 수는 있지만 해당 객체가 자신과 같은 객체인지 값을 비교할 수 없기 때문에 null을 리턴하게 된다. 따라서 역시 원하는 객체를 찾을 수 없다.


마치며
프로젝트를 진행하다 보면 이런 기본적인 내용을 다시 한번 공부하게 되는 시간이 자주 발생하는 것 같다..ㅎ 이렇게라도 기본을 다시 챙기면서 가자..ㅎ

profile
주니어 백엔드 개발자. 까먹는다 기록하자!

1개의 댓글

comment-user-thumbnail
2023년 7월 24일

많은 도움이 되었습니다, 감사합니다.

답글 달기