Статьи

Класс объектов Guava: Equals, HashCode и ToString

Если вам достаточно повезло с использованием JDK 7 , новый доступный класс Objects является очевидным ( по крайней мере для меня ) выбором для реализации «общих» методов объекта Java, таких как equals (Object) [with Objects.equals (Object, Object) ) ], hashCode ()Objects.hashCode (Object) или Objects.hash (Object…) ] и toString ()Objects.toString (Object) ] для надлежащего переопределения реализаций объекта по умолчанию. Я написал посты об использовании класса Objects: JDK 7: Новый класс объектов и Java 7 Objects-Powered Objects Equals .

Если вы еще не используете Java 7, лучшим выбором могут быть сборщики Apache Commons ToStringBuilder и EqualsBuilder и HashCodeBuilder (если вы используете версию Java до J2SE 5) или Guava (если вы используете J2SE 5 или позже). В этой статье я расскажу об использовании класса объектов Guava Objects для реализации трех общих методов equals , hashCode и toString() .

Без помощи Гуавы или другой библиотеки три общих метода, обсуждаемые в этом посте, часто выделяются, как показано в следующем листинге кода. Эти методы были созданы с помощью бета-версии NetBeans 7.1.

TraditionalEmployee

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package dustin.examples;
 
import java.util.Calendar;
 
/**
 * Simple employee class using NetBeans-generated 'common' methods
 * implementations that are typical of many such implementations created
 * without Guava or other library.
 *
 * @author Dustin
 */
public class TraditionalEmployee
{
   public enum Gender{ FEMALE, MALE };
 
   private final String lastName;
   private final String firstName;
   private final String employerName;
   private final Gender gender;
 
   /**
    * Create an instance of me.
    *
    * @param newLastName The new last name my instance will have.
    * @param newFirstName The new first name my instance will have.
    * @param newEmployerName The employer name my instance will have.
    * @param newGender The gender of my instance.
    */
   public TraditionalEmployee(
      final String newLastName, final String newFirstName,
      final String newEmployerName, final Gender newGender)
   {
      this.lastName = newLastName;
      this.firstName = newFirstName;
      this.employerName = newEmployerName;
      this.gender = newGender;
   }
 
   public String getEmployerName()
   {
      return this.employerName;
   }
 
   public String getFirstName()
   {
      return this.firstName;
   }
 
   public Gender getGender()
   {
      return this.gender;
   }
 
   public String getLastName()
   {
      return this.lastName;
   }
 
   /**
    * NetBeans-generated method that compares provided object to me for equality.
    *
    * @param obj Object to be compared to me for equality.
    * @return {@code true} if provided object is considered equal to me or
    *    {@code false} if provided object is not considered equal to me.
    */
   @Override
   public boolean equals(Object obj)
   {
      if (obj == null)
      {
         return false;
      }
      if (getClass() != obj.getClass())
      {
         return false;
      }
      final TraditionalEmployee other = (TraditionalEmployee) obj;
      if ((this.lastName == null) ? (other.lastName != null) : !this.lastName.equals(other.lastName))
      {
         return false;
      }
      if ((this.firstName == null) ? (other.firstName != null) : !this.firstName.equals(other.firstName))
      {
         return false;
      }
      if ((this.employerName == null) ? (other.employerName != null) : !this.employerName.equals(other.employerName))
      {
         return false;
      }
      if (this.gender != other.gender)
      {
         return false;
      }
      return true;
   }
 
   /**
    * NetBeans-generated method that provides hash code of this employee instance.
    *
    * @return My hash code.
    */
   @Override
   public int hashCode()
   {
      int hash = 3;
      hash = 19 * hash + (this.lastName != null ? this.lastName.hashCode() : 0);
      hash = 19 * hash + (this.firstName != null ? this.firstName.hashCode() : 0);
      hash = 19 * hash + (this.employerName != null ? this.employerName.hashCode() : 0);
      hash = 19 * hash + (this.gender != null ? this.gender.hashCode() : 0);
      return hash;
   }
 
   /**
    * NetBeans-generated method that provides String representation of employee
    * instance.
    *
    * @return My String representation.
    */
   @Override
   public String toString()
   {
      return  'TraditionalEmployee{' + 'lastName=' + lastName + ', firstName=' + firstName
            + ', employerName=' + employerName + ', gender=' + gender +  '}';
   }
}

Несмотря на то, что бета-версия NetBeans 7.1 сделала тяжелую работу, этот код все еще необходимо поддерживать и сделать его более читабельным. Следующий класс — это тот же класс, но с общими методами на основе Guava вместо сгенерированных NetBeans «типичных» реализаций, показанных выше.

GuavaEmployee

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
package dustin.examples;
 
/**
 * Simple employee class using Guava-powered 'common' methods implementations.
 *
 * I explicitly scope the com.google.common.base.Objects class here to avoid the
 * inherent name collision with the java.util.Objects class.
 *
 * @author Dustin
 */
public class GuavaEmployee
{
   public enum Gender{ FEMALE, MALE };
 
   private final String lastName;
   private final String firstName;
   private final String employerName;
   private final TraditionalEmployee.Gender gender;
 
   /**
    * Create an instance of me.
    *
    * @param newLastName The new last name my instance will have.
    * @param newFirstName The new first name my instance will have.
    * @param newEmployerName The employer name my instance will have.
    * @param newGender The gender of my instance.
    */
   public GuavaEmployee(
      final String newLastName, final String newFirstName,
      final String newEmployerName, final TraditionalEmployee.Gender newGender)
   {
      this.lastName = newLastName;
      this.firstName = newFirstName;
      this.employerName = newEmployerName;
      this.gender = newGender;
   }
 
   public String getEmployerName()
   {
      return this.employerName;
   }
 
   public String getFirstName()
   {
      return this.firstName;
   }
 
   public TraditionalEmployee.Gender getGender()
   {
      return this.gender;
   }
 
   public String getLastName()
   {
      return this.lastName;
   }
 
   /**
    * Using Guava to compare provided object to me for equality.
    *
    * @param obj Object to be compared to me for equality.
    * @return {@code true} if provided object is considered equal to me or
    *    {@code false} if provided object is not considered equal to me.
    */
   @Override
   public boolean equals(Object obj)
   {
      if (obj == null)
      {
         return false;
      }
      if (getClass() != obj.getClass())
      {
         return false;
      }
      final GuavaEmployee other = (GuavaEmployee) obj;
 
      return   com.google.common.base.Objects.equal(this.lastName, other.lastName)
            && com.google.common.base.Objects.equal(this.firstName, other.firstName)
            && com.google.common.base.Objects.equal(this.employerName, other.employerName)
            && com.google.common.base.Objects.equal(this.gender, other.gender);
   }
 
   /**
    * Uses Guava to assist in providing hash code of this employee instance.
    *
    * @return My hash code.
    */
   @Override
   public int hashCode()
   {
      return com.google.common.base.Objects.hashCode(
                this.lastName, this.firstName, this.employerName, this.gender);
   }
 
   /**
    * Method using Guava to provide String representation of this employee
    * instance.
    *
    * @return My String representation.
    */
   @Override
   public String toString()
   {
      return com.google.common.base.Objects.toStringHelper(this)
                .addValue(this.lastName)
                .addValue(this.firstName)
                .addValue(this.employerName)
                .addValue(this.gender)
                .toString();
   }
}

Как доказывает приведенный выше код, использование Guava улучшает читаемость реализаций трех распространенных методов. Единственная вещь, которая не так хороша, — это необходимость явно включать класс Objects Guava в код, чтобы избежать конфликта имен с классом объектов Java SE 7. Конечно, если вы не используете Java 7, то это не проблема, и если вы используете Java 7, скорее всего, в любом случае следует использовать стандартную версию.

Вывод

Guava предоставляет хороший подход для создания более безопасных и более читаемых общих методов через класс Objects . Хотя вместо этого я буду использовать новый класс java.util.Objects для проектов JDK 7, класс Guava com.google.common.base.Objects предоставляет хорошую альтернативу для работы в версиях Java до JDK 7.

Ссылка: класс объектов Guava: Equals, HashCode и ToString от нашего партнера по JCG Дастина Маркса из блога Inspired by Actual Events .