JDK 7: The New Objects Class

It was announced approximately 18 months ago that JDK 7 would include a new java.util.Objects class that would "hold commonly-written utility methods." As part of this announcement, Joe Darcy asked the community, "What other utility methods would have broad enough use and applicability to go into a common java.util class?" There were forums and posts on the matter and I blogged about this forthcoming class. The JDK 7 preview release includes this class and it can be tried out now. In this post, I look at use of most of the methods provided by this class and look at how NetBeans 6.9 already uses this class in some of its auto-generated methods.

The java.util.Objects class is new to JDK 7 and its Javadoc states that the class is "since 1.7" and describes the class as: "This class consists of static utility methods for operating on objects. These utilities include null-safe or null-tolerant methods for computing the hash code of an object, returning a string for an object, and comparing two objects." There are currently nine static methods with public accessibility: a compare method, a deepEquals method (for comparing arrays for equality), an equals method, a hash code calculation method potentially for multiple objects, a hashCode method for a single object, overloaded requireNonNull methods, and overloaded toString methods.

There are some general themes associated with the methods provided by the new Objects class. The methods tend to increase null safety. In other words, use of these methods is something I'd be happy to add to my list of Java NullPointerException handling techniques. When one desires an instance's hash code or string representation or one wants to compare an instance to another instance, it is typically prudent to first check the object reference for null to avoid a NullPointerException occurring before the hash code, String representation, or comparison can be made. By moving these common operations out of one of the objects being acted upon into this separate Objects class, the external class can check for null rather than forcing the object itself to be checked explicitly every time.

The second major theme relevant to the methods of the new Objects class is that these methods encapsulate functionality that many developers have written on their own or that other non-standard libraries supply. This new Objects class provides a relatively concise, standardized approach to invoking this common functionality. As will be seen in this post, it makes it easy to clean up commonly implemented methods such as overridden toString, equals, and hashCode methods and to enforce non-null parameter contract constraints.

Unlike the ever-present java.lang.Object class, but like fellow classes in the java.util package, the java.util.Objects class must be explicitly imported in Java classes that make use of it. The Objects class does NOT need to be explicitly imported when used in Groovy because Groovy automatically imports classes in the java.util package. Because all examples in this post are written in Java, the java.util.Objects class will be explicitly imported in each class.

The next code listing is for a simple Person class. I generated this class's hashCode() and equals(Object) methods using NetBeans 6.9's "Insert Code" mechanism and was pleased to see that (assuming I had the Java 1.7 Platform set for my project) the relevant Objects class methods were used in these automatically generated methods. The automatically generated toString() did not make use of either of the overloaded Objects.toString() methods. I assumed that might have been because the Person class has only String attributes and these don't need to be checked for null before the implicit toString() is invoked on them. However, even when I added a more complex data type that would lead to an NPE when its implicit toString() was called, NetBeans did not use the Objects.toString() method to avoid the potential NPE.

Person.java

package dustin.examples;

import java.util.Objects;

/**
 * Simple class to be used in demonstration of JDK 7's java.util.Objects class.
 *
 * @author Dustin
 */
public class Person
{
   private String lastName;

   private String firstName;

   /**
    * Parameterized constructor for instantiating a Person. Both a non-null first
    * name and a non-null last name must be provided (no "Madonna" or "Lindsay"
    * or "Seal" allowed here [unless you pass one name as an empty String]).
    *
    * @param newLastName This Person instance's last name; must not be null.
    * @param newFirstName This Person instance's first name; must not be null.
    * @throws NullPointerException Thrown if either provided name parameter is
    *   null.
    */
   public Person(final String newLastName, final String newFirstName)
   {
      this.lastName = Objects.requireNonNull(newLastName, "Last name cannot be null.");
      this.firstName = Objects.requireNonNull(newFirstName, "First name cannot be null.");
   }

   public String getLastName()
   {
      return this.lastName;
   }

   public String getFirstName()
   {
      return this.firstName;
   }

   /**
    * NetBeans 6.9-generated equals(Object) method. It used
    * Objects.equals(Object, Object) to avoid the need to check for null on any
    * references before comparing them. This can really clean up equals method
    * implementations.
    *
    * @param obj Object to be compared to me for equality.
    * @return {@code true} if the provided object is considered equal to me;
    *    {@code false} otherwise.
    */
   public boolean equals(Object obj)
   {
      if (obj == null)
      {
         return false;
      }
      if (getClass() != obj.getClass())
      {
         return false;
      }
      final Person other = (Person) obj;
      if (!Objects.equals(this.lastName, other.lastName))
      {
         return false;
      }
      if (!Objects.equals(this.firstName, other.firstName))
      {
         return false;
      }
      return true;
   }

   /**
    * NetBeans 6.9-generated hashCode(). It used Objects.hashCode(Object)!
    * 
    * @return Hash code for this instance.
    */
   public int hashCode()
   {
      int hash = 5;
      hash = 97 * hash + Objects.hashCode(this.lastName);
      hash = 97 * hash + Objects.hashCode(this.firstName);
      return hash;
   }

   @Override
   public String toString()
   {
      return this.firstName + " " + this.lastName;
   }
}

The NetBeans-generated hashCode() method makes use of Objects.hashCode(Object) to get the individual hash codes of each of its constituent attributes. The advantage of doing this is that each attribute does not need to be checked for null before asking for its hash code. The null checking is still implicitly performed (and zero is returned if the object is null), but the code is much cleaner.

The NetBeans-generated equals(Object) method makes use of Objects.equals(Object, Object) to safely compare the current object's attributes to the provided object's attributes. This method is null-safe and returns true if both attributes being compared are null and returns false if either is null without the other being null. If both compared attributes are non-null, then a standard equality check is made. The Objects.equals(Object,Object) method provides consistent null-safe equality checking with much cleaner code than could be done before this.

The Person class listed above is used by the next code listing, which is the main code listing demonstrating the majority of the methods on the new Objects class.

ObjectsClassDemo.java

Related:
1 2 Page 1
Page 1 of 2