etc./StackOverFlow

Java 열거형 멤버 비교: == 또는 equals()?

청렴결백한 만능 재주꾼 2021. 12. 26. 04:07
반응형

질문자 :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 Gonzo

enum == 를 사용할 수 있습니까?

== 를 사용하여 인스턴스를 비교할 수 있는 엄격한 인스턴스 컨트롤이 있습니다. 다음은 언어 사양에서 제공하는 보증입니다(제가 강조).

JLS 8.9 열거형

열거형에는 열거형 상수에 의해 정의된 인스턴스 이외의 인스턴스가 없습니다.

열거형 형식을 명시적으로 인스턴스화하려고 시도하는 것은 컴파일 타임 오류입니다. Enumfinal 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 컴파일러가 이를 찾는 것은 추가적인 안전성을 추가하지 않습니다.

하지만:

  1. 사실 == 내 마음에 NPE가 발생합니다 결코이의 단점 == . 좀처럼 필요가 없어야합니다 enum 타입이 될 null 여분의 상태가 당신을 통해 표현 할 수 있기 때문에, null 단지에 추가 할 수 있습니다 enum 추가 인스턴스로는. 예기치 않게 null == 자동으로 false로 평가하는 것보다 NPE가 더 좋습니다. 따라서 런타임에 더 안전하다는 의견에 동의하지 않습니다. enum 값을 @Nullable 설정하지 않는 습관을 들이는 것이 좋습니다.
  2. ==더 빠르다 는 주장도 가짜입니다. 대부분의 경우 컴파일 시간 유형이 열거형 클래스인 변수에 대해 .equals() == 와 같다는 것을 알 수 있습니다( enumequals() 메서드는 재정의되지 않음) 함수 호출을 최적화할 수 있습니다. 컴파일러가 현재 이 작업을 수행하는지 확실하지 않지만 그렇지 않고 Java 전체의 성능 문제로 판명되면 100,000명의 Java 프로그래머가 프로그래밍 스타일을 적절하게 변경하는 것보다 컴파일러를 수정하겠습니다. 특정 컴파일러 버전의 성능 특성.
  3. enums 은 개체입니다. 다른 모든 객체 유형의 경우 표준 비교는 == 아니라 .equals() 입니다. enums 대해 예외를 만드는 것은 위험하다고 생각합니다 enum 을 열거형이 아닌 클래스로 리팩토링하는 경우 실수로 equals() == 사용하여 Objects를 비교할 수 있기 때문입니다. 이러한 리팩토링의 경우 위에서부터 작동하는 포인트가 잘못된 것입니다. == 사용이 올바른지 확인하려면 해당 값이 enum 인지 기본형인지 확인해야 합니다. enum 이 아닌 클래스라면 잘못되었지만 코드가 계속 컴파일되기 때문에 놓치기 쉽습니다. .equals() 사용이 잘못된 유일한 경우는 해당 값이 기본 값인 경우입니다. 이 경우 코드가 컴파일되지 않으므로 놓치기가 훨씬 더 어렵습니다. 따라서 .equals() 는 올바른 것으로 식별하기가 훨씬 쉽고 향후 리팩토링에 대해 더 안전합니다.

실제로 Java 언어는 왼쪽 값에서 .equals()를 호출하고 개체 ID에 대해 별도의 연산자를 도입하기 위해 Objects에 ==를 정의해야 한다고 생각하지만 Java가 정의된 방식은 그렇지 않습니다.

요약하면, 나는 여전히 인수가 enum 유형에 .equals() 를 사용하는 데 찬성한다고 생각합니다.


Tobias

equals 대신 == 를 사용하는 것을 선호합니다.

여기에서 이미 논의된 다른 이유 외에도 버그를 깨닫지 못한 채 도입할 수 있는 다른 이유가 있습니다. 정확히 동일하지만 분리된 패키지에 있는 이 열거형이 있다고 가정합니다(일반적이지는 않지만 발생할 수 있음).

첫 번째 열거형 :

 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로 이 테스트를 여러 번 실행했습니다. "=="는 그 어느 때보다 약간 더 빠릅니다.


ChrisCantrell

enum의 경우 둘 다 정확하고 옳습니다!!


Suraj Chandran

Sonar 규칙 중 하나는 Enum values should be compared with "==" 입니다. 이유는 다음과 같습니다.

enum은 Object이고 모든 Java 개발자는 == 를 사용하여 Object의 내용을 비교해서는 안 된다는 equals() 를 사용하여 enum 값의 동등성을 테스트하는 것은 완벽하게 유효합니다. 동시에 열거형에 ==

  • equals() 동일한 예상 비교(내용)를 제공합니다.

  • equals() 보다 널 안전합니다.

  • 런타임 검사가 아닌 컴파일 시간(정적) 검사를 제공합니다.

이러한 이유로 == equals() 보다 선호되어야 합니다.

마지막으로, == equals() 보다 더 읽기 쉽습니다(덜 장황함).


Mohsen Zamani

열거형 상수를 비교하기 위해 == 이외의 것을 사용하는 것은 넌센스입니다. class 객체를 equals와 비교 equals 하지 마세요!

그러나 Sun JDK 6u10 및 이전 버전에는 역사적인 이유로 흥미로울 수 있는 불쾌한 버그( BugId 6277781)가 있었습니다. == 를 적절하게 사용하는 것을 막았지만, 이것은 다소 코너 케이스입니다.


Tomas

public 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 Lingen

polygenelubricants 답변을 보완하고 싶습니다.

저는 개인적으로 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

반응형