오~~~늘은 Enum의 동등비교에 대해 알아볼 예정이다!! 그런데,, 왜?! 갑자기 이런 주제를 똭하고 가져왔는지 궁금해할 수 있다.
코드리뷰를 진행하다보니.. 다들 equals, == 을 혼용해서 사용하고 있었다. 쉽게 아래 예제를 보면
// A 개발자
if (moveStatus.equals(MoveStatus.CANCEL)) {
return CommonResponse.fail("애니웨이 실패했습니다람쥐");
}
// B 개발자
if(MoveStatus.CANCEL.equals(moveStatus)){
return CommonResponse.fail("애니웨이 실패했습니다금바리");
}
// C 개발자
if(MoveStatus.CANCEL == moveStatus){
return CommonResponse.fail("애니웨이 실패했습니다랑어");
}
이런 현상인 것이다.. 뭔가 king받기 때문에, 통일이 되었으면 좋겠다라는 생각이 들어 블로그에 올려보려고 한다.
대충살자.. 아서처럼
귀가 있어도 관자놀이로 노래 듣는 아서처럼 대충살려고 했으나.. 너무 궁금했다!!!
킹명주: "왜 equals를 쓰셨나요?"
A 개발자: "선행되어 있는 코드를 참고 했는데, equals를 쓰고 있더라구여.. 맞춰서 개발했어요!!"
킹명주: "왜 ==을 쓰셨나요?"
B 개발자: "그냥 습관적으로 쓰게 되었어요! 문제가 있을까요?!"
야레야레.. 이래선 안되겠다.. 내가 이 문제를 해결하겠다!! 위에서 보았던 예제처럼 "equals"와 "=="의 Time Performance, Null Safety, Keyboard Man hour를 각각 비교하겠다.
equals, == 비교
performance를 비교하기 전, enum의 equals와 == 에 대해 좀 더 알아보고 넘어가려고 한다. 사실 Enum의 경우 equals, == 모두 사용 가능하기 때문에 무엇을 사용해도 사실 상관은 없다.
실제로 Enum class를 확인해보면 equals 함수는
public final boolean equals(Object other) {
return this==other;
}
== 연산자로 비교하고 있다. 그러니 equals나 == 이나 모두 똑같은 결과를 기대할 수 있다.
그런데 여기서 궁금한 점이 같은 reference type(String, Long ...)의 경우 enum과 동일하게 heap에 객체를 저장하고 있는데, 왜 reference type은 == 으로 정확한 결과를 얻을 수 없고 enum은 == 으로 정확한 결과를 얻을 수 있는 것일까?
reference type에서 == 을 사용하게 되면, 주소값을 비교하게 된다. reference type의 경우 heap에 객체를 저장하는 것을 맞지만 stack 영역에 변수를 관리하는 형태이다.
그렇기 때문에 같은 값이라도 주소값이 항상 같음을 보장할 수 없다. 그래서
@IntrinsicCandidate
public static boolean equals(byte[] value, byte[] other) {
if (value.length == other.length) {
for (int i = 0; i < value.length; i++) {
if (value[i] != other[i]) {
return false;
}
}
return true;
}
return false;
}
값 하나하나 비교해주는 equals를 사용하라는 것이다.
반면, enum은 heap 메모리에 저장되는 것은 맞으나 public static fianl로 선언이 된다.
public enum Days{
MONDAY,
TUESDAY,
WEDNESDAY;
}
위의 내용을 컴파일 후, class파일을 분해하면
Compiled from " Days.java"
public final class Constants extends java.lang.Enum{
public static final Days MONDAY;
public static final Days TUESDAY;
public static final Days WEDNESDAY;
public static Days [] values();
public static Days valueOf(java.lang.String);
static {};
}
static final로 선언된 것을 확인 할 수 있다. 이 말은 곧, 클래스 로딩 시점에 한번만 생성하여 해당 상수를 참조할 때마다 동일한 인스턴스에 대한 참조를 반환한다는 것이다.
그래서 enum의 경우 '==' 비교가 가능한 것이다. 화두가 길었다.. 이제 equals와 ==에 대한 성능 차이를 알아보고, 어떤 방식을 사용하는게 더 효율적일지 고민해보자!!
비교분석
1. Time Performance
for문을 n번 돌면서 equals와 ==의 시간을 비교해보려고 한다.
실험 환경은 아래와 같다.
- Timer: Springframwork StopWatch class
- 산식: 총 50번 실행 후, 평균 값 계산
// equals time check
stopWatch.start();
for(int i =0; i<1000000; i++) {
if (MoveStatus.CANCEL.equals(moveStatus)) {
cancelCount++;
}
}
stopWatch.stop();
System.out.printf("'equals' = %s m/s",stopWatch.prettyPrint(TimeUnit.MILLISECONDS));
// == time check
stopWatch.start();
for(int i =0; i<1000000; i++) {
if (moveStatus == MoveStatus.CANCEL) {
cancelCount++;
}
}
stopWatch.stop();
System.out.printf("'==' = %s m/s",stopWatch.prettyPrint(TimeUnit.MILLISECONDS));
사실 equals도 결국 == 연산자를 사용하기 때문에, 시간 측정에서는 유의미한 결과를 얻을 수 없었다.(둘 다 빠름 ㅎ)
그러므로, 시간 성능 때문에 ==을 써요~ 라는 말은 좀 잘못된 것같다.
2. Null Safety
Null Safety란 NullPointerException 을 방지할 수 있는가? 에 대한 내용이다.
MoveStatus test = null;
System.out.println(MoveStatus.CANCEL == test);
System.out.println(MoveStatus.CANCEL.equals(test));
System.out.println(test.equals(MoveStatus.CANCEL));
== 연산자와 Enum 상수.equals(변수) 의 경우 Null Safety 하다.
반면, 변수.equals(Enum상수)의 경우 NullPointerException이 발생하면서 null에 unsafety하다.
그러므로 마지막 방법을 제외하고는 ==, equals 비교의 경우 둘 다 null safety한 방법이다.
3. Keyboard Man hour
뭐가 좋은건지 모르겠다... 시간도 동일하고 둘 다 null safety한데,, 뭘 써야할까?
그래서 키보드 공수를 바탕으로 무슨 방법이 더 좋은지 도출해보겠다.
==
==의 경우 동일한 키 두번만 누르면 되기 때문에 손가락 공수가 거의 들지 않는다.
equals
equals의 경우 6번의 이동이 필요하며 == 에 비해 손가락 공수가 많이 들어가는 편이다. 그러나, 자동완성을 사용하는 경우, e만 입력해도 equals 함수를 완성할 수 있기 때문에 손가락 공수가 거의 들지 않는다.
결론
시간: '==' >= equals
null safety: '==', equals
keyboard man hours: '==' >= equals
사실상, 둘 다 맞는 방법이고 뭐가 더 좋다 나쁘다 이런것은 없다. 그러나, 필자는 앞으로는 == 을 사용할 계획이다.
그 이유는 == 연산자가 오래전 부터 사용해왔기 때문에 많은 사람들에게 좀 더 명확한 의미를 전달할 수 있다고 생각한다. equals 함수가 만들어 진 배경도 결국에는 == 으로 정확한 결과를 도출할 수 없는 객체가 있기 때문에 만들어진 것이라고 생각한다. (뇌피셜)
그렇기 때문에 굳이 == 을 사용하지 않고 equals를 사용할 이유가 있을까? 라는 생각이 들었다. enum은 특히 더 그런것이 equals 함수 구현한 것을 들어가보면 == 으로 return 값을 주고 있다. 이말인즉슨 == 연산자를 영어로 쓰는 느낌인 것이다.
만약, equals를 쓴다면 꼭 enum 상수가 앞에오도록 사용하면 될 것 같다.
오늘의 실험실 공장 끝~
'JAVA' 카테고리의 다른 글
Java에서 Stack Class는 함정카드다. (4) | 2024.06.13 |
---|---|
Java 8 Functional Interface에 대해 알아보자. (0) | 2023.10.31 |