Ich bin gespannt, was die Leute hier über die Verwendung von org.apache.commons.lang.builder
EqualsBuilder
/ HashCodeBuilder
zur Implementierung von equals
/ denken
hashCode
. Wäre es eine bessere Praxis als selbst zu schreiben? Spielt es gut mit Hibernate? Was ist deine Meinung?
155
reflectionEquals
undreflectionHashcode
Funktionen verführen. Die Leistung ist ein absoluter Killer.Antworten:
Die Commons / Lang-Builder sind großartig und ich benutze sie seit Jahren ohne merklichen Leistungsaufwand (mit und ohne Ruhezustand). Aber wie Alain schreibt, ist der Guavenweg noch schöner:
Hier ist ein Beispiel Bean:
Hier sind equals () und hashCode (), die mit Commons / Lang implementiert wurden:
und hier mit Java 7 oder höher (inspiriert von Guava):
Hinweis: Dieser Code bezog sich ursprünglich auf Guava. Wie in Kommentaren bereits erwähnt, wurde diese Funktionalität inzwischen im JDK eingeführt, sodass Guava nicht mehr benötigt wird.
Wie Sie sehen, ist die Guava / JDK-Version kürzer und vermeidet überflüssige Hilfsobjekte. Bei Gleichheit kann die Auswertung sogar kurzgeschlossen werden, wenn ein früherer
Object.equals()
Aufruf false zurückgibt (um fair zu sein: commons / lang hat eineObjectUtils.equals(obj1, obj2)
Methode mit identischer Semantik, die anstelle von verwendet werden könnteEqualsBuilder
wie oben einen Kurzschluss zuzulassen).Also: Ja, die Commons Lang Builder sind gegenüber manuell erstellten
equals()
und sehr vorzuziehenhashCode()
Methoden Methoden (oder diesen schrecklichen Monstern, die Eclipse für Sie generiert) , aber die Java 7+ / Guava-Versionen sind noch besser.Und ein Hinweis zu Hibernate:
Seien Sie vorsichtig bei der Verwendung von Lazy Collections in Ihren Implementierungen equals (), hashCode () und toString (). Das wird kläglich scheitern, wenn Sie keine offene Sitzung haben.
Hinweis (ungefähr gleich ()):
a) In beiden Versionen von equals () oben möchten Sie möglicherweise auch eine oder beide dieser Verknüpfungen verwenden:
b) Abhängig von Ihrer Interpretation des equals () - Vertrags können Sie auch die Zeile (n) ändern.
zu
Wenn Sie die zweite Version verwenden, möchten Sie wahrscheinlich auch
super(equals())
Ihreequals()
Methode aufrufen . Die Meinungen sind hier unterschiedlich, das Thema wird in dieser Frage diskutiert:(obwohl es darum geht
hashCode()
, gilt das gleiche fürequals()
)Hinweis (inspiriert von Kommentar von Kayahr )
Objects.hashCode(..)
(genau wie der BasiswertArrays.hashCode(...)
) kann schlecht funktionieren, wenn Sie viele primitive Felder haben. In solchen FällenEqualsBuilder
kann tatsächlich die bessere Lösung sein.quelle
equals
. Guava konvertiert alle Werte in Objekte, commons-lang erstellt nur ein einziges neues Objekt.Leute, wach auf! Seit Java 7 gibt es in der Standardbibliothek Hilfsmethoden für equals und hashCode . Ihre Verwendung entspricht voll und ganz der Verwendung von Guava-Methoden.
quelle
Wenn Sie nicht von einer Bibliothek eines Drittanbieters abhängig sein möchten (möglicherweise führen Sie ein Gerät mit begrenzten Ressourcen aus) und sogar keine eigenen Methoden eingeben möchten, können Sie die IDE auch die Aufgabe ausführen lassen, z. B. bei der Verwendung von Eclipse
Sie werden ‚native‘ Code erhalten , die Sie können , wie Sie konfigurieren wie und welche Sie müssen auf Veränderungen unterstützen.
Beispiel (Eclipse Juno):
quelle
equals
. Wenn Sie nicht von einer Bibliothek eines Drittanbieters abhängig sein möchten, schreiben Sie die einzeilige Methode wieObjects.equal
Sie. Selbst wenn es nur ein- oder zweimal verwendet wird, verbessert es den Code erheblich!equals
/hashCode
einzeilige Methoden ???EqualsBuilder und HashCodeBuilder haben zwei Hauptaspekte, die sich von manuell geschriebenem Code unterscheiden:
Der EqualsBuilder und der HashCodeBuilder erleichtern den Vergleich von Feldern, die null sein können. Mit manuell geschriebenem Code entsteht eine Menge Boilerplate.
Der EqualsBuilder erstellt dagegen eine Instanz pro equals-Methodenaufruf. Wenn Ihre Gleichheitsmethoden häufig aufgerufen werden, werden viele Instanzen erstellt.
Für den Ruhezustand machen die Implementierung von equals und hashCode keinen Unterschied. Sie sind nur ein Implementierungsdetail. Bei fast allen Domänenobjekten, die im Ruhezustand geladen sind, kann der Laufzeitaufwand (auch ohne Escape-Analyse) des Builders ignoriert werden . Der Datenbank- und Kommunikationsaufwand wird erheblich sein.
Wie Skaffman erwähnte, kann die Reflection-Version nicht im Produktionscode verwendet werden. Die Reflexion wird zu langsam sein und die "Implementierung" wird nicht für alle außer den einfachsten Klassen korrekt sein. Die Berücksichtigung aller Mitglieder ist ebenfalls gefährlich, da neu eingeführte Mitglieder das Verhalten der Methode "Gleich" ändern. Die Reflection-Version kann im Testcode hilfreich sein.
quelle
Wenn Sie nicht selbst schreiben möchten, besteht auch die Möglichkeit, Google Guava (früher Google Collections) zu verwenden.
quelle
Wenn Sie sich nur mit der Entity-Bean befassen, bei der id ein Primärschlüssel ist, können Sie dies vereinfachen.
quelle
Meiner Meinung nach spielt es mit Hibernate nicht gut, insbesondere mit den Beispielen aus der Antwort, in denen Länge, Name und Kinder für eine Entität verglichen werden. Hibernate empfiehlt die Verwendung eines Geschäftsschlüssels für equals () und hashCode () zu verwenden, und sie haben ihre Gründe. Wenn Sie für Ihren Geschäftsschlüssel den Generator auto equals () und hashCode () verwenden, ist dies in Ordnung. Es müssen nur die Leistungsprobleme wie oben erwähnt berücksichtigt werden. Aber die Leute nutzen normalerweise alle Eigenschaften, was IMO sehr falsch ist. Zum Beispiel arbeite ich gerade an einem Projekt, in dem Entitäten mit Pojomatic mit @AutoProperty geschrieben werden, was ich für ein wirklich schlechtes Muster halte.
Die beiden Hauptszenarien für die Verwendung von hashCode () und equals () sind:
Nehmen wir also an, unsere Entität sieht folgendermaßen aus:
Beide sind dieselbe Entität für den Ruhezustand, die zu einem bestimmten Zeitpunkt aus einer Sitzung abgerufen wurden (ID und Klasse / Tabelle sind gleich). Aber was haben wir, wenn wir auto equals () a hashCode () auf allen Requisiten implementieren?
Für ein 99% -Projekt, das ich mache, verwenden wir die folgende Implementierung von equals () und hashCode (), die einmal in der Basisentitätsklasse geschrieben wurden, was mit den Hibernate-Konzepten übereinstimmt:
Für die vorübergehende Entität mache ich dasselbe, was der Ruhezustand im Persistenzschritt tun wird, dh. Ich benutze die Instanzübereinstimmung. Für die persistenten Objekte vergleiche ich den eindeutigen Schlüssel, der die Tabelle / ID ist (ich verwende niemals zusammengesetzte Schlüssel).
quelle
Nur für den Fall, dass andere es nützlich finden, habe ich mir diese Helper-Klasse für die Berechnung von Hash-Code ausgedacht, die den oben erwähnten zusätzlichen Aufwand für die Objekterstellung vermeidet (tatsächlich ist der Aufwand für die Objects.hash () -Methode sogar noch größer, wenn Sie dies getan haben Vererbung, da auf jeder Ebene ein neues Array erstellt wird!).
Anwendungsbeispiel:
Der HashCode-Helfer:
Ich habe herausgefunden, dass 10 die maximal vernünftige Anzahl von Eigenschaften in einem Domänenmodell ist. Wenn Sie mehr haben, sollten Sie darüber nachdenken, mehr Klassen umzugestalten und einzuführen, anstatt einen Haufen von Zeichenfolgen und Grundelementen beizubehalten.
Die Nachteile sind: Es ist nicht nützlich, wenn Sie hauptsächlich Grundelemente und / oder Arrays haben, die Sie tief hashen müssen. (Normalerweise ist dies der Fall, wenn Sie mit flachen (Übertragungs-) Objekten arbeiten müssen, die außerhalb Ihrer Kontrolle liegen.)
quelle