Guava’s Objects Class: Equals, HashCode, and ToString

If you are fortunate enough to be using JDK 7, the newly available Objects class is the obvious (at least to me) choice for implementing the ‘common’ Java object methods such as equals(Object) [with Objects.equals(Object,Object)], hashCode() [with Objects.hashCode(Object) or Objects.hash(Object...)], and toString() [with Objects.toString(Object)] to appropriately override the default Object implementations. I have written posts about using Objects class: JDK 7: The New Objects Class and Java 7 Objects-Powered Compact Equals.

If you’re not yet using Java 7, your best choices might be the Apache Commons builders ToStringBuilder and EqualsBuilder and HashCodeBuilder (if you’re using a version of Java prior to J2SE 5) or Guava (if you’re using J2SE 5 or later). In this post, I look at using Guava‘s Objects class to implement the three common methods equals, hashCode, and toString().

Without Guava or other library to help, the three common methods discussed in this post are often highlighted as shown in the next code listing. These methods were generated with NetBeans 7.1 beta.

TraditionalEmployee
 

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 +  '}';
   }
}

Although NetBeans 7.1 beta did the heavy lifting here, this code still must be maintained and can be made more readable. The next class is the same class, but with Guava-powered common methods instead of the NetBeans-generated ‘typical’ implementations shown above.

GuavaEmployee
 

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();
   }
}

As the code above proves, the use of Guava improves the readability of the implementations of the three common methods. The only thing that’s not so nice is the need to explicitly scope Guava’s Objects class in the code to avoid a naming collision with Java SE 7′s Objects class. Of course, if one is not using Java 7, then this is not an issue and if one is using Java 7, it’s most likely that the standard version should be used instead anyway.

Conclusion

Guava provides a nice approach for building safer and more readable common methods via its Objects class. Although I’ll use the new java.util.Objects class instead for JDK 7 projects, Guava’s com.google.common.base.Objects class provides a nice alternative for working in versions of Java prior to JDK 7.
 

Reference: Guava’s Objects Class: Equals, HashCode, and ToString from our JCG partner Dustin Marx at the Inspired by Actual Events blog.

Related Whitepaper:

Bulletproof Java Code: A Practical Strategy for Developing Functional, Reliable, and Secure Java Code

Use Java? If you do, you know that Java software can be used to drive application logic of Web services or Web applications. Perhaps you use it for desktop applications? Or, embedded devices? Whatever your use of Java code, functional errors are the enemy!

To combat this enemy, your team might already perform functional testing. Even so, you're taking significant risks if you have not yet implemented a comprehensive team-wide quality management strategy. Such a strategy alleviates reliability, security, and performance problems to ensure that your code is free of functionality errors.Read this article to learn about this simple four-step strategy that is proven to make Java code more reliable, more secure, and easier to maintain.

Get it Now!  

Leave a Reply


× three = 21



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

15,153 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books