Apache Commons EqualsBuilder und HashCodeBuilder

Ich habe zuvor im Apache Commons ToStringBuilder gebloggt und darüber gesprochen, wie ein Großteil der Langeweile, die normalerweise mit der Implementierung von toString-Methoden verbunden ist, wegfällt. Die Implementierung von toString () bietet zwar einen erheblichen Nutzen beim Debuggen und Protokollieren und wird in Joshua Blochs Effective Java (Punkt 10 in der zweiten Ausgabe) empfohlen, hat jedoch normalerweise keine Auswirkungen auf die Logik und Leistung einer Anwendung (es sei denn, toString () ist speziell als Teil der Logik verwendet). In Object sind jedoch Methoden definiert, die sich sowohl auf die Logik als auch auf die Leistung in einer Anwendung auswirken. Zwei davon [equals () und hashCode ()] werden in diesem Blogeintrag erläutert.

Während sich hashCode () und equals () in der Regel stärker auf Logik und Leistung auswirken als toString (), ist die korrekte Implementierung häufig schwieriger. Viele Java-Entwickler folgen den Anweisungen von Joshua Bloch zur Implementierung dieser Methoden, wie in Effective Java beschrieben (wobei 18 Seiten der 315 Kernseiten diesen beiden Methoden gewidmet sind). Beispiel: Der Artikel Hashtables: Wenn Sie Ihr eigenes Schlüsselobjekt in einer Hashtable erstellen, fasst Be Careful die Regeln zusammen, die eine equals () -Methode einhalten sollte, und gibt Blochs Empfehlungen in Java-Code. In dem Artikel Hashing it Out: Entwerfen von hashCode () und equals () wird effektiv und korrekt erläutert, wie diese beiden wichtigen Methoden (equals und hashCode) implementiert werden. Die am einfachsten zu merkende Regel ist natürlich, dass, wenn eine dieser beiden Methoden überschrieben wird, auch die andere verwendet werden sollte.

Da es schwierig sein kann, hashCode () und equals () korrekt zu implementieren, ist es hilfreich, wiederverwendbare Implementierungen davon als Teil des Apache Commons Lang Builder-Pakets bereitzustellen (dasselbe Paket, das den zuvor erwähnten ToStringBuilder enthält). Noch besser ist, dass diese Implementierungen explizit geschrieben wurden, um den häufig zitierten Ratschlägen von Bloch zu folgen, wie in der Javadoc-Dokumentation für EqualsBuilder und HashCodeBuilder beschrieben.

In meinem Blogeintrag zu ToStringBuilder habe ich seine Reflexionsfähigkeiten demonstriert und intensiv genutzt. Ich bin weniger geneigt, Reflexionsfunktionen in Verbindung mit EqualsBuilder und HashCodeBuilder zu verwenden, da diese Methoden häufig in Situationen verwendet werden, in denen die Leistung ein Hauptproblem darstellt. Details zum Anwenden der reflexionsbasierten Verwendung von EqualsBuilder und HashCodeBuilder finden Sie hier und in den jeweiligen Javadoc-Beschreibungen für diese Klassen.

Der in diesem Blogeintrag verwendete Beispielcode ist sehr einfach und zerkratzt nur die Oberfläche dessen, was EqualsBuilder und HashCodeBuilder leisten können. Der Beispielcode bietet jedoch ein einfaches Beispiel für die allgemeine Verwendung dieser beiden Klassen. Ein zusätzlicher Bonus ist, dass der Code auch die Commons CLI und Commons Lang ToStringBuilder in Aktion demonstriert.

Die erste zu betrachtende Klasse ist die SimpleDataExample- Klasse, da diese Klasse tatsächlich die Implementierungen der Methoden equals () und hashCode () enthält , die EqualsBuilder bzw. HashCodeBuilder verwenden. In diesem Beispiel wird auch ToStringBuilder verwendet, um die toString () -Methode zu implementieren .

package dustin.builders; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.ToStringBuilder; /** * This is a "simple" data class intended for demonstration of Apache Commons * EqualsBuilder and HashCodeBuilder. This is an immutable class and all of its * state must be provided at construction. * * @author Dustin */ public class SimpleDataExample { /** ID associated with this class. */ private final Long id; /** Name of data (does not need to be unique). */ private final String name; /** * Constructor accepting arguments to populate my state. * * @param newId ID of this object instance. * @param newName Name of this object instance. */ public SimpleDataExample( final Long newId, final String newName) { this.id = newId; this.name = newName; } /** Private constructor - not meant to be used. */ private SimpleDataExample() { this.id = null; this.name = null; } /** * Provide my ID. * * @return My ID. */ public Long getId() { return this.id; } /** * Provide my name. * * @return My name. */ public String getName() { return this.name; } /** * My hash code implementation. * * @return My hash code. */ @Override public int hashCode() { return new HashCodeBuilder() .append(this.id) .append(this.name) .toHashCode(); } /** * My implementation of equals() method. The NetBeans-generated version is * left in place (but commented out) to notice the order of magnitude of code * required without EqualsBuilder. * * @param obj The object to compare to me for equality. * @return true if the other object and I are equal; false otherwise. */ @Override public boolean equals(Object obj) { if (obj instanceof SimpleDataExample == false) { return false; } if (this == obj) { return true; } final SimpleDataExample otherObject = (SimpleDataExample) obj; return new EqualsBuilder() .append(this.id, otherObject.id) .append(this.name, otherObject.name) .isEquals(); /* if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final SimpleDataExample other = (SimpleDataExample) obj; if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) { return false; } if (this.name != other.name && (this.name == null || !this.name.equals(other.name))) { return false; } return true; */ } /** * Provide String representation of me. * * @return String representation of me. */ @Override public String toString() { return new ToStringBuilder(this) .append("ID", this.id) .append("Name", this.name) .toString(); } } 

Der Code, der aus Sicht dieses Blogeintrags am interessantesten ist, befindet sich alle in der obigen Klasse, insbesondere in den Methoden equals () und hashCode () . In der nächsten Codeliste wird eine "Test" -Klasse aufgeführt, die die oben in einer ArrayList und einem HashSet definierte einfache Datenklasse verwendet, abhängig von dem Befehlszeilenargument, das für die main () -Methode bereitgestellt wird. Dies demonstriert die Commons CLI, vor allem aber die Verwendung der Methoden equals () und hashCode () in der Datenklasse.