Ich weiß, dass Java-Enums zu Klassen mit privaten Konstruktoren und einer Reihe öffentlicher statischer Mitglieder kompiliert werden. Beim Vergleich zweier Mitglieder einer bestimmten Aufzählung habe ich immer .equals()
z
public useEnums(SomeEnum a)
{
if(a.equals(SomeEnum.SOME_ENUM_VALUE))
{
...
}
...
}
Ich bin jedoch gerade auf Code ==
gestoßen , der den Operator equals anstelle von .equals () verwendet:
public useEnums2(SomeEnum a)
{
if(a == SomeEnum.SOME_ENUM_VALUE)
{
...
}
...
}
Welchen Operator sollte ich verwenden?
Antworten:
Beide sind technisch korrekt. Wenn Sie sich den Quellcode ansehen
.equals()
, wird er einfach aufgeschoben==
.Ich benutze
==
jedoch, da dies null sicher sein wird.quelle
.equals()
Sie ihn eingeben? Ich weiß, dass ich es nicht tue.Kann
==
verwendet werdenenum
?Ja: Aufzählungen verfügen über strenge Instanzsteuerelemente, mit denen Sie
==
Instanzen vergleichen können. Hier ist die Garantie der Sprachspezifikation (Hervorhebung von mir):Diese Garantie ist stark genug, die Josh Bloch empfiehlt. Wenn Sie darauf bestehen, das Singleton-Muster zu verwenden, können Sie es am besten implementieren, indem Sie ein einzelnes Element verwenden
enum
(siehe: Effektive Java 2nd Edition, Punkt 3: Erzwingen Sie die Singleton-Eigenschaft mit a privater Konstruktor oder ein Aufzählungstyp ; auch Thread-Sicherheit in Singleton )Was sind die Unterschiede zwischen
==
undequals
?Zur Erinnerung muss gesagt werden, dass dies im Allgemeinen
==
KEINE Alternative istequals
. Wenn dies jedoch der Fall ist (z. B. beienum
), sind zwei wichtige Unterschiede zu berücksichtigen:==
wirft nieNullPointerException
==
wird zur Kompilierungszeit einer Typpompatibilitätsprüfung unterzogenSollte
==
gegebenenfalls verwendet werden?Bloch erwähnt ausdrücklich, dass unveränderliche Klassen, die die richtige Kontrolle über ihre Instanzen haben, ihren Kunden garantieren können, dass sie
==
verwendbar sind.enum
wird ausdrücklich als Beispiel erwähnt.Zusammenfassend sind die Argumente für die Verwendung von
==
onenum
:quelle
Color nothing = null;
ist IMHO ein Fehler und sollte behoben werden, Ihre Enum hat zwei Werte, nicht drei ( siehe Tom Hawtins Kommentar) 4. Zum Zeitpunkt der Kompilierung ist es sicherer : OK,equals
würde aber trotzdem zurückkehrenfalse
. Am Ende kaufe ich es nicht, ich bevorzugeequals()
die Lesbarkeit (siehe Kevins Kommentar).foo.equals(bar)
lesbarer halten alsfoo == bar
Das
==
Vergleichen von zwei Aufzählungswerten funktioniert, da für jede Aufzählungskonstante nur ein Objekt vorhanden ist.Nebenbei bemerkt, es ist eigentlich nicht nötig
==
, null-sicheren Code zu schreiben, wenn Sie Ihren folgenden Code schreibenequals()
:Dies ist eine bewährte Methode, die als Konstanten von links vergleichen bekannt ist und die Sie unbedingt befolgen sollten.
quelle
.equals()
Zeichenfolgenwerte eingebe, aber ich denke immer noch, dass es eine beschissene Art ist, null-sicheren Code zu schreiben. Ich hätte viel lieber einen Operator (oder eine Methode, aber ich weiß, dass [null object] .equals in Java aufgrund der Funktionsweise des Punktoperators niemals null-sicher sein wird), der unabhängig von der immer null-sicher ist Reihenfolge, in der es verwendet wird. Semantisch sollte der Operator "equals" immer pendeln.?.
) verfügt, werde ich diese Vorgehensweise weiterhin verwenden, wenn ich sie mit Konstanten vergleiche, und TBH finde ich sie nicht beschissen, vielleicht nur weniger "natürlich".null
Aufzählung ist normalerweise ein Fehler. Sie haben diese Aufzählung aller möglichen Werte und hier ist eine andere!@Nullable
, halte ich Compare Constants From The Left für ein Antimuster, da es Unklarheiten darüber verbreitet, welche Werte null sein können oder nicht. Aufzählungstypen sollten fast nie sein@Nullable
, daher wäre ein Nullwert ein Programmierfehler. In einem solchen Fall ist es umso wahrscheinlicher, dass Sie Ihren Programmierfehler dort finden, wo Sie zugelassen haben, dass er null ist, je früher Sie NPE auslösen. "Best Practice ... dem Sie unbedingt folgen sollten" ist also eindeutig falsch, wenn es um Aufzählungstypen geht.Wie andere gesagt haben, funktionieren beide
==
und.equals()
in den meisten Fällen. Die Gewissheit über die Kompilierungszeit, dass Sie keine völlig unterschiedlichen Objekttypen vergleichen, auf die andere hingewiesen haben, ist gültig und vorteilhaft. Die besondere Art des Fehlers beim Vergleichen von Objekten mit zwei verschiedenen Kompilierungszeittypen wird jedoch auch von FindBugs (und wahrscheinlich auch von) gefunden Eclipse / IntelliJ-Inspektionen zur Kompilierungszeit), sodass der Java-Compiler, der dies feststellt, nicht so viel zusätzliche Sicherheit bietet.Jedoch:
==
ich nie an NPE denke, ist ein Nachteil von==
. Es sollte kaum jemals eine Notwendigkeit fürenum
Typen gebennull
, da jeder zusätzliche Status, über den Sie möglicherweise ausdrücken möchten,null
einfachenum
als zusätzliche Instanz zu hinzugefügt werden kann . Wenn es unerwartet istnull
, hätte ich lieber eine NPE als==
stillschweigend falsch zu bewerten. Daher bin ich nicht der Meinung, dass es zur Laufzeit sicherer ist . Es ist besser, sich daran zu gewöhnen, niemalsenum
Werte sein zu lassen@Nullable
.==
das schneller ist, ist auch falsch. In den meisten Fällen rufen Sie.equals()
eine Variable auf, deren Kompilierungszeittyp die Enum-Klasse ist, und in diesen Fällen kann der Compiler wissen, dass dies dasselbe ist wie==
(daenum
dieequals()
Methode von an nicht überschrieben werden kann) und den Funktionsaufruf optimieren Weg. Ich bin mir nicht sicher, ob der Compiler dies derzeit tut, aber wenn dies nicht der Fall ist und sich insgesamt als Leistungsproblem in Java herausstellt, würde ich den Compiler lieber reparieren, als 100.000 Java-Programmierer ihren Programmierstil entsprechend ändern zu lassen Leistungsmerkmale einer bestimmten Compilerversion.enums
sind Objekte. Für alle anderen Objekttypen ist der Standardvergleich.equals()
nicht==
. Ich denke, es ist gefährlich, eine Ausnahme zu machen,enums
weil Sie möglicherweise versehentlich Objekte mit==
anstatt vergleichenequals()
, insbesondere wenn Sie eineenum
in eine Nicht-Enum-Klasse umgestalten . Im Falle eines solchen Refactorings ist der Punkt Es funktioniert von oben falsch. Um sich davon zu überzeugen, dass eine Verwendung von==
korrekt ist, müssen Sie prüfen, ob der betreffende Wert entweder einenum
oder ein Grundelement ist. Wenn es keineenum
Klasse wäre, wäre es falsch, aber leicht zu übersehen, da der Code immer noch kompiliert würde. Der einzige Fall, wenn eine Verwendung von.equals()
wäre falsch, wenn die fraglichen Werte primitiv wären; In diesem Fall würde der Code nicht kompiliert, sodass es viel schwieriger ist, ihn zu übersehen. Daher.equals()
ist es viel einfacher, als korrekt zu identifizieren, und es ist sicherer gegen zukünftige Refactorings.Ich denke tatsächlich, dass die Java-Sprache == für Objekte definiert haben sollte, um .equals () auf der linken Seite aufzurufen und einen separaten Operator für die Objektidentität einzuführen, aber so wurde Java nicht definiert.
Zusammenfassend denke ich immer noch, dass die Argumente für die Verwendung
.equals()
fürenum
Typen sprechen .quelle
enum
alsswitch
Ziel verwenden, damit sie etwas Besonderes sind.String
s sind auch etwas Besonderes.Ich benutze lieber
==
anstelle vonequals
:Ein weiterer Grund, zusätzlich zu den anderen, die hier bereits besprochen wurden, ist, dass Sie einen Fehler einführen können, ohne es zu merken. Angenommen, Sie haben diese Aufzählung, die genau gleich ist, aber in getrennten Paketen (es ist nicht üblich, aber es könnte passieren):
Erste Aufzählung :
Zweite Aufzählung:
Nehmen wir dann an, Sie verwenden die Gleichheit wie
item.category
folgt,first.pckg.Category
aber Sie importieren die zweite Aufzählung (second.pckg.Category
) anstelle der ersten, ohne es zu merken:So werden Sie immer
false
fällig, ist eine andere Aufzählung, obwohl Sie wahr erwarten, weilitem.getCategory()
istJAZZ
. Und es könnte etwas schwierig zu sehen sein.Wenn Sie stattdessen den Operator verwenden
==
, wird ein Kompilierungsfehler angezeigt:quelle
Hier ist ein grober Timing-Test, um die beiden zu vergleichen:
Kommentieren Sie die IFs einzeln aus. Hier sind die beiden Vergleiche von oben in zerlegtem Bytecode:
Der erste (gleich) führt einen virtuellen Aufruf aus und testet den Rückgabewert vom Stack. Das zweite (==) vergleicht die Objektadressen direkt vom Stapel. Im ersten Fall gibt es mehr Aktivität.
Ich habe diesen Test mehrmals mit beiden IFs nacheinander durchgeführt. Das "==" ist etwas schneller.
quelle
Im Falle einer Aufzählung sind beide richtig und richtig !!
quelle
tl; dr
Eine weitere Option ist die
Objects.equals
Dienstprogrammmethode.Objects.equals
für Null-SicherheitEine dritte Option ist die statische
equals
Methode für dieObjects
Dienstprogrammklasse , die Java 7 und höher hinzugefügt wurde .Beispiel
Hier ist ein Beispiel mit der
Month
Aufzählung.Leistungen
Ich finde ein paar Vorteile für diese Methode:
true
false
NullPointerException
Wie es funktioniert
Welche Logik wird verwendet
Objects.equals
?Überzeugen Sie sich selbst vom Java 10-Quellcode von OpenJDK :
quelle
Es
==
ist Unsinn, etwas anderes zu verwenden, als Enum-Konstanten zu vergleichen. Es ist wie ein Vergleich vonclass
Objekten mitequals
- tu es nicht!Es gab jedoch einen bösen Fehler (BugId 6277781 ) in Sun JDK 6u10 und früher, der aus historischen Gründen interessant sein könnte. Dieser Fehler verhinderte die ordnungsgemäße Verwendung
==
bei deserialisierten Aufzählungen, obwohl dies wohl eher ein Eckfall ist.quelle
Aufzählungen sind Klassen, die eine Instanz (wie Singletons) für jede von
public static final field
(unveränderlich) deklarierte Aufzählungskonstante zurückgeben, sodass der==
Operator verwendet werden kann, um ihre Gleichheit zu überprüfen, anstatt eineequals()
Methode zu verwendenquelle
Der Grund, warum Aufzählungen mit == problemlos funktionieren, liegt darin, dass jede definierte Instanz auch ein Singleton ist. Der Identitätsvergleich mit == funktioniert also immer.
Wenn Sie jedoch == verwenden, weil es mit Aufzählungen funktioniert, ist Ihr gesamter Code eng mit der Verwendung dieser Aufzählung verbunden.
Zum Beispiel: Enums können eine Schnittstelle implementieren. Angenommen, Sie verwenden derzeit eine Aufzählung, die Interface1 implementiert. Wenn es später jemand ändert oder eine neue Klasse Impl1 als Implementierung derselben Schnittstelle einführt. Wenn Sie dann anfangen, Instanzen von Impl1 zu verwenden, müssen Sie aufgrund der vorherigen Verwendung von == viel Code ändern und testen.
Daher ist es am besten, eine bewährte Methode zu befolgen, es sei denn, es gibt einen vertretbaren Gewinn.
quelle
Eine der Sonarregeln ist
Enum values should be compared with "=="
. Die Gründe sind folgende:Last but not least ist die
==
on-Aufzählung wohl besser lesbar (weniger ausführlich) alsequals()
.quelle
Kurz gesagt, beide haben Vor- und Nachteile.
Einerseits hat es Vorteile
==
, wie in den anderen Antworten beschrieben.Wenn Sie jedoch aus irgendeinem Grund die Aufzählungen durch einen anderen Ansatz ersetzen (normale Klasseninstanzen), haben
==
Sie Bisse verwendet. (BTDT.)quelle
Ich möchte Polygenschmierstoffe ergänzen Antwort:
Ich persönlich bevorzuge equals (). Aber es gibt die Typpompatibilitätsprüfung. Was ich für eine wichtige Einschränkung halte.
Deklarieren und verwenden Sie eine benutzerdefinierte Funktion in Ihrer Enumeration, um die Typkompatibilität zur Kompilierungszeit zu überprüfen.
Damit haben Sie alle Vorteile beider Lösungen: NPE-Schutz, einfach zu lesender Code und Typpompatibilitätsprüfung zur Kompilierungszeit.
Ich empfehle auch, einen UNDEFINED-Wert für enum hinzuzufügen.
quelle
==
? Mit erhalten==
Sie NPE-Schutz, einfach zu lesenden Code und Kompatibilitätsprüfung für die Kompilierungszeit, und Sie erhalten all diese, ohne benutzerdefinierte gleichwertige Methoden zu schreiben.UNDEFINED
Wert ist wahrscheinlich eine gute Idee. Natürlich würden Sie in Java 8Optional
stattdessen ein verwenden.==
kann werfen,NullPointerException
wenn ein primitiver Typ mit seiner Klassenversion verglichen wird. Zum Beispiel:quelle
==
die nie werfen kannNPEs
. Diese Frage hat genug Antworten, aber dies kann eine gute Referenz sein, falls jemand wie ich, der 2 Stunden gebraucht hat, um zu Bug / Feature zu gelangen, dies liest.