Comparing Java enum members: = = or equals()?
Wiem, że enumery Javy są kompilowane do klas z prywatnymi konstruktorami i grupą publicznych statycznych członków. Porównując dwa człony danego enum, zawsze używałem .equals()
, np.
public useEnums(SomeEnum a)
{
if(a.equals(SomeEnum.SOME_ENUM_VALUE))
{
...
}
...
}
Natknąłem się jednak na jakiś kod, który zamiast tego używa operatora równości ==
.equals ():
public useEnums2(SomeEnum a)
{
if(a == SomeEnum.SOME_ENUM_VALUE)
{
...
}
...
}
Jakiego operatora powinienem używać?
14 answers
Oba są poprawne technicznie. Jeśli spojrzysz na kod źródłowy .equals()
, po prostu przesuwa się do ==
.
Używam ==
, jednak, ponieważ będzie to null bezpieczne.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-10 15:55:55
Czy można użyć ==
na enum
?
Tak: enums mają ścisłe kontrolki instancji, które pozwalają używać ==
do porównywania instancji. Oto gwarancja zapewniona przez specyfikację języka (podkreślona przeze mnie):
JLS 8.9 Enums
Typ enum nie ma instancji innych niż te zdefiniowane przez jego stałe enum.
Próba jawnego utworzenia instancji typu enum jest błędem w czasie kompilacji. Metoda
final clone
wEnum
zapewnia, żeenum
stałe nigdy nie mogą być klonowane, a specjalne traktowanie przez mechanizm serializacji zapewnia, że duplikaty instancji nigdy nie są tworzone w wyniku deserializacji. Zabronione jest tworzenie refleksyjnych instancji typów enum. Razem te cztery rzeczy zapewniają, że żadne instancje typuenum
nie istnieją poza tymi zdefiniowanymi przez stałeenum
.Ponieważ istnieje tylko jedna instancja każdej
enum
stałej, dopuszczalne jest użycie operatora==
zamiastequals
metoda porównująca dwa odniesienia do obiektów, jeśli wiadomo, że przynajmniej jedno z nich odnosi się doenum
stałej. (Metodaequals
WEnum
jest metodąfinal
, która po prostu wywołujesuper.equals
na swoim argumencie i zwraca wynik, wykonując w ten sposób porównanie tożsamości.)
Ta gwarancja jest na tyle silna, że Josh Bloch zaleca, że jeśli nalegasz na użycie wzoru Singletona, najlepszym sposobem jego wdrożenia jest użycie jednoelementowego enum
(Zobacz: {55]}skutecznego Java 2nd Edition, Pozycja 3: egzekwowanie własności singleton za pomocą prywatnego konstruktora lub typu enum; także bezpieczeństwo wątków w Singleton )
Jakie są różnice między ==
i equals
?
Dla przypomnienia, należy powiedzieć, że ogólnie ==
nie jest realną alternatywą dla equals
. Kiedy jednak tak jest (np. z enum
), należy wziąć pod uwagę dwie ważne różnice:
==
nigdy nie rzucaj NullPointerException
enum Color { BLACK, WHITE };
Color nothing = null;
if (nothing == Color.BLACK); // runs fine
if (nothing.equals(Color.BLACK)); // throws NullPointerException
==
jest test zgodności typu w czasie kompilacji
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!
Czy {[2] } należy stosować, gdy ma zastosowanie?
Bloch wyraźnie wspomina, że niezmienne klasy, które mają właściwą kontrolę nad swoimi instancjami, mogą zagwarantować swoim klientom, że==
jest użyteczna. enum
jest specjalnie wspomniany dla przykładu.
Item 1: rozważ statyczne metody fabryczne zamiast konstruktorów
[...] pozwala klasie niezmiennej złożyć gwarancję że nie istnieją dwie równe instancje:
a.equals(b)
wtedy i tylko wtedy, gdya==b
. Jeśli klasa składa taką gwarancję, to jej klienci mogą użyć operatora==
zamiast metodyequals(Object)
, co może skutkować lepszą wydajnością. Typy Enum zapewniają tę gwarancję.
Podsumowując, argumenty za użyciem ==
na enum
są następujące:
- To działa.
Jest szybszy.
Jest bezpieczniej w czasie ucieczki.
- to bezpieczniejsze w czasie kompilacji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-07 09:06:45
Użycie ==
do porównania dwóch wartości enum działa, ponieważ dla każdej stałej enum jest tylko jeden obiekt.
Na marginesie, w rzeczywistości nie ma potrzeby używania ==
do napisania bezpiecznego kodu null, jeśli napiszesz swój equals()
w następujący sposób:
public useEnums(SomeEnum a)
{
if(SomeEnum.SOME_ENUM_VALUE.equals(a))
{
...
}
...
}
Jest to najlepsza praktyka znana jako Porównaj Stałe Z Lewej , którą zdecydowanie powinieneś przestrzegać.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-17 17:53:22
Jak mówili inni, zarówno ==
jak i .equals()
działają w większości przypadków. Pewność w czasie kompilacji, że nie porównujesz zupełnie różnych typów obiektów, które inni wskazali, jest poprawna i korzystna, jednak szczególny rodzaj błędu porównywania obiektów dwóch różnych typów kompilacji może być również znaleziony przez FindBugs (i prawdopodobnie przez Eclipse/IntelliJ compile time inspections), więc znalezienie kompilatora Javy nie dodaje zbyt wiele dodatkowych informacji bezpieczeństwo.
Jednakże:
- fakt, że
==
nigdy nie rzuca NPE w mój umysł jestwadą==
. Nie powinno być potrzeby, aby typyenum
byłynull
, ponieważ każdy dodatkowy stan, który chcesz wyrazić za pomocąnull
, można po prostu dodać doenum
jako dodatkową instancję. Jeśli jest nieoczekiwanienull
, wolałbym mieć NPE niż==
po cichu Oceniać na false. Dlatego nie zgadzam się z opinią jest bezpieczniej w czasie trwania; jest lepiej aby wejść w nawyk nigdy nie pozwalaćenum
wartościom@Nullable
. - argument, że
==
jest szybszy jest również fałszywy. W większości przypadków wywołujesz.equals()
na zmiennej, której typem czasu kompilacji jest klasa enum, a w tych przypadkach kompilator może wiedzieć, że jest to to samo co==
(ponieważ metodaenum
sequals()
nie może zostać nadpisana) i może zoptymalizować wywołanie funkcji. Nie jestem pewien, czy kompilator obecnie to robi, ale jeśli tak nie jest, a okazuje się, że jest to wydajność problem w Javie ogólnie rzecz biorąc, to wolałbym naprawić kompilator, niż mieć 100,000 programistów Java zmienić swój styl programowania, aby dopasować się do charakterystyki wydajności konkretnej wersji kompilatora. -
enums
są obiektami. Dla wszystkich innych typów obiektów standardowym porównaniem jest.equals()
, a nie==
. Myślę, że niebezpiecznie jest zrobić wyjątek dlaenums
, ponieważ może skończyć się przypadkowym porównaniem obiektów z==
zamiastequals()
, szczególnie jeśli refaktorujeszenum
do klasy nie-enum. W przypadku takiego refaktoryzacji punkt Działa z góry jest błędny. Aby przekonać siebie, że użycie {[0] } jest poprawne, musisz sprawdzić, czy dana wartość jest alboenum
, albo prymitywną; jeśli byłaby to klasa nie-enum
, byłoby to błędne, ale łatwe do przeoczenia, ponieważ kod wciąż byłby kompilowany. Jedyny przypadek, w którym użycie.equals()
byłoby błędne, to gdyby Dane wartości były prymitywne; w takim przypadku kod nie kompilowałby się, więc trudniej go przeoczyć. Stąd {[1] } jest dużo łatwiejsze do zidentyfikowania jako poprawne i jest bezpieczniejsze przed przyszłymi refaktoringami.
Myślę, że język Java powinien mieć zdefiniowane = = na obiektach do wywołania .equals () po lewej stronie wartości i wprowadzić oddzielny operator dla tożsamości obiektu, ale nie tak została zdefiniowana Java.
Podsumowując, nadal uważam, że argumenty przemawiają za używaniem .equals()
dla typów enum
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-04 03:43:54
Oto prymitywny test czasu, aby porównać te dwa:
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());
}
}
Komentuj IFs pojedynczo. Oto dwa porównania z góry w demontowanym kodzie bajtowym:
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
First (equals) wykonuje wirtualne wywołanie i testuje wartość logiczną zwracaną ze stosu. Drugi ( = = ) porównuje adresy obiektów bezpośrednio ze stosu. W pierwszym przypadku jest więcej aktywności.
Przeprowadziłem ten test kilka razy z obu IFs po kolei. "=="Jest zawsze tak lekko szybciej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-14 21:19:26
Wolę używać ==
zamiast equals
:
Innym powodem, oprócz innych już omówionych tutaj, jest to, że możesz wprowadzić błąd nie zdając sobie z tego sprawy. Załóżmy, że masz te liczby, które są dokładnie takie same, ale w oddzielonych pacakges (nie jest to powszechne, ale może się zdarzyć): {]}
Pierwszy enum :
package first.pckg
public enum Category {
JAZZ,
ROCK,
POP,
POP_ROCK
}
Drugie enum:
package second.pckg
public enum Category {
JAZZ,
ROCK,
POP,
POP_ROCK
}
Wtedy Załóżmy, że używasz równości jak next w item.category
czyli {[7] } ale importujesz drugie enum (second.pckg.Category
) zamiast pierwszego nie zdając sobie z tego sprawy:
import second.pckg.Category;
...
Category.JAZZ.equals(item.getCategory())
Więc dostaniesz allways false
due jest innym enum, chociaż oczekujesz prawdy, ponieważ item.getCategory()
jest JAZZ
. I to może być trochę trudne do zobaczenia.
Jeśli zamiast tego użyjesz operatora ==
, pojawi się błąd kompilacji:
Operator = = nie może być zastosowany do " second.pckg.Kategoria", " pierwsza.pckg.Kategoria "
import second.pckg.Category;
...
Category.JAZZ == item.getCategory()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-21 07:31:45
W przypadku enum oba są poprawne i poprawne!!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-23 13:03:10
Używanie czegokolwiek innego niż ==
do porównywania stałych enum jest nonsensem. To jak porównywanie class
obiektów z equals
– nie rób tego!
Jednak pojawił się paskudny błąd (BugId 6277781) W Sun JDK 6u10 i wcześniej może to być interesujące ze względów historycznych. Ten błąd uniemożliwił prawidłowe użycie ==
Na deserializowanych enumach, chociaż prawdopodobnie jest to przypadek narożny.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-26 20:40:01
Enums są klasami, które zwracają jedną instancję (jak singletony) dla każdej stałej wyliczenia zadeklarowanej przez public static final field
(immutable) tak, że operator ==
może być użyty do sprawdzenia ich równości zamiast metody equals()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-07 15:21:13
Krótko mówiąc, oba mają plusy i minusy.
Z jednej strony ma zalety używania ==
, jak opisano w innych odpowiedziach.
Z drugiej strony, jeśli z jakiegokolwiek powodu zastąpisz enums innym podejściem (normalne instancje klas), po użyciu ==
. (BTDT.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-05 20:05:39
Powodem, dla którego enums działa łatwo z = = jest to, że każda zdefiniowana instancja jest również singletonem. Więc porównanie tożsamości za pomocą = = zawsze będzie działać.
Ale używanie = = ponieważ działa z enums oznacza, że cały Twój kod jest ściśle powiązany z używaniem tego enum.
Na przykład: Enums może zaimplementować interfejs. Załóżmy, że obecnie używasz enum, które implementuje interfejs 1. Jeśli później ktoś ją zmieni lub wprowadzi nową klasę Impl1 jako implementację tego samego interfejsu. Następnie, jeśli zaczniesz używać instancji Impl1, będziesz miał dużo kodu do zmiany i przetestowania z powodu wcześniejszego użycia ==.
Dlatego najlepiej stosować się do tego, co uważa się za dobrą praktykę, chyba że istnieje uzasadniony zysk.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-12 03:19:17
Chcę uzupełnić polygenelubricants odpowiedź:
Ja osobiście wolę equals (). Ale sprawdzanie zgodności typu. Co moim zdaniem jest ważnym ograniczeniem.
Aby sprawdzić zgodność typów w czasie kompilacji, zadeklaruj i użyj niestandardowej funkcji w swoim enum.
public boolean isEquals(enumVariable) // compare constant from left
public static boolean areEqual(enumVariable, enumVariable2) // compare two variable
Dzięki temu masz wszystkie zalety obu rozwiązań: ochronę NPE, łatwy do odczytania kod i sprawdzenie zgodności typu w czasie kompilacji.
Polecam również dodać UNDEFINED wartość dla enum.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-17 08:43:54
Enum w środku jest zbiorem stałych liczb całkowitych. "=="jest tak samo poprawne i poprawne, jak gdybyś porównał dwie liczby całkowite.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-15 21:24:42
Chciałbym wyraźnie podkreślić tę specyficzną różnicę między operatorem ==
i metodą equals()
:
Metoda equals()
ma na celu sprawdzenie, czy zawartość obiektu(obiektów), do których odnoszą się zmienne odniesienia, jest taka sama.
Operator ==
sprawdza, czy odnośne zmienne odnoszą się do tego samego obiektu.
To do klasy implementującej należy zapewnienie tego zróżnicowania w zależności od potrzeb podanie.
W przeciwnym razie domyślne zachowanie będzie dostarczane przez klasę Object
(w Javie), gdzie jak wyjaśniono w http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Object.html#equals(java.lang.Object):
Metoda
equals
dla klasyObject
implementuje najbardziej rozróżniającą możliwą relację równoważności na obiektach; to znaczy dla dowolnych wartości odniesienia innych niż nullx
iy
, metoda ta zwracatrue
wtedy i tylko wtedy, gdyx
iy
odnoszą się do ten sam obiekt (x == y
ma wartośćtrue
).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-19 22:51:21