질문자 :Matt Ball
Java 열거형이 개인 생성자와 많은 공용 정적 멤버가 있는 클래스로 컴파일된다는 것을 알고 있습니다. 주어진 열거형의 두 멤버를 비교할 때 저는 항상 .equals()
public useEnums(SomeEnum a) { if(a.equals(SomeEnum.SOME_ENUM_VALUE)) { ... } ... }
그러나 방금 .equals() 대신 ==
를 사용하는 일부 코드를 발견했습니다.
public useEnums2(SomeEnum a) { if(a == SomeEnum.SOME_ENUM_VALUE) { ... } ... }
어떤 연산자를 사용해야 합니까?
둘 다 기술적으로 맞습니다. .equals()
의 소스 코드를 보면 단순히 ==
합니다.
==
사용하는데, 이는 null 안전이 될 것이기 때문입니다.
Reverend Gonzoenum
==
를 사용할 수 있습니까?
==
를 사용하여 인스턴스를 비교할 수 있는 엄격한 인스턴스 컨트롤이 있습니다. 다음은 언어 사양에서 제공하는 보증입니다(제가 강조).
열거형에는 열거형 상수에 의해 정의된 인스턴스 이외의 인스턴스가 없습니다.
열거형 형식을 명시적으로 인스턴스화하려고 시도하는 것은 컴파일 타임 오류입니다. Enum
의 final clone
방법은 enum
상수를 복제할 수 없도록 하고 직렬화 메커니즘에 의한 특수 처리는 역직렬화의 결과로 중복 인스턴스가 생성되지 않도록 합니다. 열거형 유형의 반사 인스턴스화는 금지됩니다. 이 네 가지를 함께 사용 enum
상수에 의해 정의된 것 이상으로 enum
enum
상수의 인스턴스가 하나만 있기 때문에 두 개체 참조를 비교할 때 둘 중 하나 이상이 enum
상수를 equals
메서드 대신 ==
연산자를 사용할 수 있습니다. ( Enum
equals
메소드 super.equals
를 호출하고 결과를 반환하여 동일성 비교를 수행하는 final
메소드입니다.)
이 보장은 Josh Bloch가 권장할 만큼 충분히 강력합니다. 싱글톤 패턴을 사용하기를 고집한다면 이를 구현하는 가장 좋은 방법은 단일 요소 enum
을 사용하는 것입니다(Effective Java 2nd Edition, 항목 3: 다음을 사용하여 싱글톤 속성 적용 참조). 개인 생성자 또는 열거형 유형 , 또한 Singleton의 스레드 안전성 )
==
그리고 equals
의 차이점은 무엇인가요?
다시 말하지만, 일반적으로 ==
equals
의 실행 가능한 대안이 아닙니다. 그러나 ( enum
과 같은 경우) 고려해야 할 두 가지 중요한 차이점이 있습니다.
==
NullPointerException
던지지 않음
enum Color { BLACK, WHITE }; Color nothing = null; if (nothing == Color.BLACK); // runs fine if (nothing.equals(Color.BLACK)); // throws NullPointerException
==
는 컴파일 타임에 유형 호환성 검사를 받습니다.
enum Color { BLACK, WHITE }; enum Chiral { LEFT, RIGHT }; if (Color.BLACK.equals(Chiral.LEFT)); // compiles fine if (Color.BLACK == Chiral.LEFT); // DOESN'T COMPILE!!! Incompatible types!
해당되는 경우 ==
사용해야 합니까?
Bloch는 인스턴스를 적절하게 제어할 수 있는 변경할 수 없는 클래스가 ==
를 사용할 수 있음을 클라이언트에 보장할 수 있다고 구체적으로 언급했습니다. enum
이 예시로 구체적으로 언급되었습니다.
항목 1: 생성자 대신 정적 팩토리 메서드를 고려하십시오
[...] 그것은 불변 클래스가 두 개의 동일한 인스턴스가 존재하지 않는다는 것을 보장하도록 허용합니다: a.equals(b)
if and only if a==b
. 클래스가 이를 보장하는 경우 해당 클라이언트는 equals(Object)
==
연산자를 사용할 수 있으므로 성능이 향상될 수 있습니다. 열거형은 이러한 보장을 제공합니다.
enum
==
를 사용하기 위한 인수는 다음과 같습니다.
- 효과가있다.
- 더 빠릅니다.
- 런타임에 더 안전합니다.
- 컴파일 타임에 더 안전합니다.
polygenelubricants==
를 사용하여 두 열거형 값을 비교하면 효과가 있습니다. 각 열거형 상수에 대해 개체가 하나만 있기 때문입니다.
참고로, 다음과 같이 equals()
를 작성하면 null-safe 코드를 작성 ==
public useEnums(final SomeEnum a) { if (SomeEnum.SOME_ENUM_VALUE.equals(a)) { … } … }
이것은 반드시 따라야 하는 왼쪽에서 상수 비교로 알려진 모범 사례입니다.
Pascal Thivent다른 사람들이 말했듯이 ==
및 .equals()
대부분의 경우 작동합니다. 다른 사람들이 지적한 완전히 다른 유형의 개체를 비교하지 않는다는 컴파일 시간 확신은 유효하고 유익하지만 두 가지 다른 컴파일 시간 유형의 개체를 비교하는 특정 종류의 버그는 FindBugs에서도 찾을 수 있습니다. Eclipse/IntelliJ 컴파일 시간 검사), 따라서 Java 컴파일러가 이를 찾는 것은 추가적인 안전성을 추가하지 않습니다.
하지만:
- 사실
==
내 마음에 NPE가 발생합니다 결코이의 단점 ==
. 좀처럼 필요가 없어야합니다 enum
타입이 될 null
여분의 상태가 당신을 통해 표현 할 수 있기 때문에, null
단지에 추가 할 수 있습니다 enum
추가 인스턴스로는. 예기치 않게 null
==
자동으로 false로 평가하는 것보다 NPE가 더 좋습니다. 따라서 런타임에 더 안전하다는 의견에 동의하지 않습니다. enum
값을 @Nullable
설정하지 않는 습관을 들이는 것이 좋습니다. -
==
가 더 빠르다 는 주장도 가짜입니다. 대부분의 경우 컴파일 시간 유형이 열거형 클래스인 변수에 대해 .equals()
==
와 같다는 것을 알 수 있습니다( enum
의 equals()
메서드는 재정의되지 않음) 함수 호출을 최적화할 수 있습니다. 컴파일러가 현재 이 작업을 수행하는지 확실하지 않지만 그렇지 않고 Java 전체의 성능 문제로 판명되면 100,000명의 Java 프로그래머가 프로그래밍 스타일을 적절하게 변경하는 것보다 컴파일러를 수정하겠습니다. 특정 컴파일러 버전의 성능 특성. -
enums
은 개체입니다. 다른 모든 객체 유형의 경우 표준 비교는 ==
아니라 .equals()
입니다. enums
대해 예외를 만드는 것은 위험하다고 생각합니다 enum
을 열거형이 아닌 클래스로 리팩토링하는 경우 실수로 equals()
==
사용하여 Objects를 비교할 수 있기 때문입니다. 이러한 리팩토링의 경우 위에서부터 작동하는 포인트가 잘못된 것입니다. ==
사용이 올바른지 확인하려면 해당 값이 enum
인지 기본형인지 확인해야 합니다. enum
이 아닌 클래스라면 잘못되었지만 코드가 계속 컴파일되기 때문에 놓치기 쉽습니다. .equals()
사용이 잘못된 유일한 경우는 해당 값이 기본 값인 경우입니다. 이 경우 코드가 컴파일되지 않으므로 놓치기가 훨씬 더 어렵습니다. 따라서 .equals()
는 올바른 것으로 식별하기가 훨씬 쉽고 향후 리팩토링에 대해 더 안전합니다.
실제로 Java 언어는 왼쪽 값에서 .equals()를 호출하고 개체 ID에 대해 별도의 연산자를 도입하기 위해 Objects에 ==를 정의해야 한다고 생각하지만 Java가 정의된 방식은 그렇지 않습니다.
요약하면, 나는 여전히 인수가 enum
유형에 .equals()
를 사용하는 데 찬성한다고 생각합니다.
Tobiasequals
대신 ==
를 사용하는 것을 선호합니다.
여기에서 이미 논의된 다른 이유 외에도 버그를 깨닫지 못한 채 도입할 수 있는 다른 이유가 있습니다. 정확히 동일하지만 분리된 패키지에 있는 이 열거형이 있다고 가정합니다(일반적이지는 않지만 발생할 수 있음).
첫 번째 열거형 :
package first.pckg public enum Category { JAZZ, ROCK, POP, POP_ROCK }
두 번째 열거형:
package second.pckg public enum Category { JAZZ, ROCK, POP, POP_ROCK }
그런 다음에 다음과 같이 등호를 사용하는 가정 item.category
입니다 first.pckg.Category
하지만 두 번째 열거 (가져 second.pckg.Category
그것을 실현하지 않고) 대신 첫 번째 :
import second.pckg.Category; ... Category.JAZZ.equals(item.getCategory())
따라서 item.getCategory()
JAZZ
이기 때문에 true 를 기대하지만 다른 열거형으로 인해 false
가 표시됩니다. 그리고 보기가 조금 어려울 수 있습니다.
==
연산자를 사용하면 컴파일 오류가 발생합니다.
연산자 ==는 "second.pckg.Category", "first.pckg.Category"에 적용할 수 없습니다.
import second.pckg.Category; ... Category.JAZZ == item.getCategory()
Pau헐 박사
또 다른 옵션은 Objects.equals
유틸리티 메서드입니다.
Objects.equals( thisEnum , thatEnum )
null 안전을 위한 Objects.equals
.equals() 대신 같음 연산자 ==
어떤 연산자를 사용해야 합니까?
세 번째 옵션은 Java 7 이상에 추가된 Objects
유틸리티 클래스에 equals
메소드입니다.
예시
Month
열거형을 사용하는 예입니다.
boolean areEqual = Objects.equals( Month.FEBRUARY , Month.JUNE ) ; // Returns `false`.
혜택
이 방법에 몇 가지 이점이 있습니다.
작동 방식
Objects.equals
사용하는 논리는 무엇입니까?
OpenJDK 의 Java 10 소스 코드 에서 직접 확인하십시오.
return ( a == b ) || ( a != null && a.equals( b ) ) ;
Basil Bourque다음은 두 가지를 비교하기 위한 조잡한 타이밍 테스트입니다.
import java.util.Date; public class EnumCompareSpeedTest { static enum TestEnum {ONE, TWO, THREE } public static void main(String [] args) { Date before = new Date(); int c = 0; for(int y=0;y<5;++y) { for(int x=0;x<Integer.MAX_VALUE;++x) { if(TestEnum.ONE.equals(TestEnum.TWO)) {++c;} if(TestEnum.ONE == TestEnum.TWO){++c;} } } System.out.println(new Date().getTime() - before.getTime()); } }
한 번에 하나씩 IF를 주석 처리합니다. 다음은 디스어셈블된 바이트 코드에서 위의 두 가지 비교입니다.
21 getstatic EnumCompareSpeedTest$TestEnum.ONE : EnumCompareSpeedTest.TestEnum [19] 24 getstatic EnumCompareSpeedTest$TestEnum.TWO : EnumCompareSpeedTest.TestEnum [25] 27 invokevirtual EnumCompareSpeedTest$TestEnum.equals(java.lang.Object) : boolean [28] 30 ifeq 36 36 getstatic EnumCompareSpeedTest$TestEnum.ONE : EnumCompareSpeedTest.TestEnum [19] 39 getstatic EnumCompareSpeedTest$TestEnum.TWO : EnumCompareSpeedTest.TestEnum [25] 42 if_acmpne 48
첫 번째(같음)은 가상 호출을 수행하고 스택에서 반환 부울을 테스트합니다. 두 번째(==)는 스택에서 직접 개체 주소를 비교합니다. 첫 번째 경우에는 더 많은 활동이 있습니다.
나는 한 번에 하나씩 두 IF로 이 테스트를 여러 번 실행했습니다. "=="는 그 어느 때보다 약간 더 빠릅니다.
ChrisCantrellSuraj ChandranSonar 규칙 중 하나는 Enum values should be compared with "=="
입니다. 이유는 다음과 같습니다.
enum은 Object이고 모든 Java 개발자는 ==
를 사용하여 Object의 내용을 비교해서는 안 된다는 equals()
를 사용하여 enum 값의 동등성을 테스트하는 것은 완벽하게 유효합니다. 동시에 열거형에 ==
이러한 이유로 ==
equals()
보다 선호되어야 합니다.
마지막으로, ==
equals()
보다 더 읽기 쉽습니다(덜 장황함).
Mohsen Zamani열거형 상수를 비교하기 위해 ==
이외의 것을 사용하는 것은 넌센스입니다. class
객체를 equals와 비교 equals
하지 마세요!
그러나 Sun JDK 6u10 및 이전 버전에는 역사적인 이유로 흥미로울 수 있는 불쾌한 버그( BugId 6277781)가 있었습니다. ==
를 적절하게 사용하는 것을 막았지만, 이것은 다소 코너 케이스입니다.
Tomaspublic static final field
(불변)에 의해 선언된 각 열거형 상수에 대해 하나의 인스턴스(싱글톤과 같은)를 반환하는 클래스 ==
equals()
메서드를 사용하는 대신 동등성을 확인할 수 있습니다.
ΦXocę 웃 Пepeúpa ツ열거형이 ==에서 쉽게 작동하는 이유는 정의된 각 인스턴스도 싱글톤이기 때문입니다. 따라서 ==를 사용한 동일성 비교는 항상 작동합니다.
그러나 열거형과 함께 작동하기 때문에 ==를 사용하면 모든 코드가 해당 열거형의 사용과 밀접하게 결합된다는 의미입니다.
예: 열거형은 인터페이스를 구현할 수 있습니다. 현재 Interface1을 구현하는 열거형을 사용하고 있다고 가정합니다. 나중에 누군가가 그것을 변경하거나 동일한 인터페이스의 구현으로 새로운 클래스 Impl1을 도입한다면. 그런 다음 Impl1의 인스턴스를 사용하기 시작하면 이전에 ==를 사용했기 때문에 변경하고 테스트해야 할 코드가 많습니다.
따라서 정당한 이익이 없는 한 모범 사례로 간주되는 것을 따르는 것이 가장 좋습니다.
Dev Amitabh간단히 말해서 둘 다 장단점이 있습니다.
한편으로는 다른 답변에 설명된 대로 ==
를 사용하는 이점이 있습니다.
반면에 어떤 이유로든 열거형을 다른 접근 방식(일반 클래스 인스턴스)으로 ==
를 사용하면 문제가 됩니다. (BTDT.)
glglgl다른 모든 훌륭한 답변에 한 가지만 추가하십시오. 간단한 람다를 사용할 때 메서드 참조를 사용할 수 있기 때문에 ==
보다 equals
다음 람다를 고려하십시오.
Stream.of(SomeEnum.A, SomeEnum.B).anyMatch(e -> e == SomeEnum.B); Stream.of(SomeEnum.A, SomeEnum.B).anyMatch(e -> e.equals(SomeEnum.B));
나중에 다음으로 변환할 수 있습니다.
Stream.of(SomeEnum.A, SomeEnum.B).anyMatch(SomeEnum.B::equals));
Jacob van Lingenpolygenelubricants 답변을 보완하고 싶습니다.
저는 개인적으로 equals()를 선호합니다. 그러나 그것은 유형 호환성 검사를 하지 않습니다. 중요한 한계라고 생각합니다.
컴파일 시 유형 호환성 검사를 받으려면 열거형에서 사용자 정의 함수를 선언하고 사용하십시오.
public boolean isEquals(enumVariable) // compare constant from left public static boolean areEqual(enumVariable, enumVariable2) // compare two variable
이를 통해 NPE 보호, 읽기 쉬운 코드 및 컴파일 시 유형 호환성 검사와 같은 두 솔루션의 모든 이점을 얻을 수 있습니다.
또한 enum에 UNDEFINED 값을 추가하는 것이 좋습니다.
Christ출처 : http:www.stackoverflow.com/questions/1750435/comparing-java-enum-members-or-equals