Objects utility class in Java

Today I would like to quickly mention java.util.Objects class. The JavaDoc documentation for this class says:

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.

That’s all. There is nothing special or difficult in this class – similar methods were already written thousands of times by many developers all over the world. Yet I find this class very useful because it simplifies the source code and removes unnecessary code duplication. Let’s take a glimpse at its methods.

Validating input arguments

Class Objects provides 3 methods to verify if the argument passed to the method is not null.

static <T> T	Objects.requireNonNull(T obj)

Checks if the passed object is not null. If it is null, the methods throws exception.

static <T> T	Objects.requireNonNull(T obj, String message)

Checks if the passed object is not null. If it is null, the methods throws exception with the specified message.

static <T> T	Objects.requireNonNull(T obj, Supplier messageSupplier)

Checks if the passed object is not null. If it is null, the method throws exception with the message provided by supplier. Although it looks more complicated than the previous method, it has the advantage that it creates error message lazily – only when it is actually needed. Therefore, it may be a bit faster in certain situations.

These basic methods reduce the following 3 lines of code:

if (arg == null) {
    throw new NullPointerException("Argument is null.");
}

to just one:

Objects.requireNonNull(arg, "Argument is null.").

These methods are used often in JDK source code.

Null-safe output

There are also 2 very simple methods for converting objects to string.

static String	Objects.toString(Object o, String nullDefault)

If the passed object is not null, returns o.toString(). Otherwise, returns nullDefault value.

static String	Objects.toString(Object o)

The same as Objects.toString(o, “null”).

Null and non-null predicates

There are two self-explanatory methods:

static boolean	Objects.isNull(Object obj)
static boolean	Objects.nonNull(Object obj)

The only reason for their existence is that they can be used as a predicate in stream API like this:

myList.stream().map(...).filter(Objects::nonNull)...

Hash code and equals

Let’s consider following class with typical hashCode and equals methods:

class Mapping {
        private String name; // never null
        private Integer value; // can be null

        public Mapping(String name, Integer value) {
            Objects.requireNonNull(name);
            this.name = name;
            this.value = value;
        }
        
        @Override
        public int hashCode() {
            int result = name.hashCode();
            result += 3 * (value != null ? value.hashCode() : 0);
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final Mapping other = (Mapping) obj;
            return name.equals(other.name)
                    && ((value == null && other.value == null) || (value != null && value.equals(other.value)));
        }
    }

We can assume that name is never null but value can be sometimes null and we have to put some conditional code in hashCode and equals methods. It is nothing hard here but it takes a moment to verify if the implementation of these methods is correct.

Class Objects provides few convenient methods to simplify the code:

static int	Objects.hashCode(Object o)

If the object is not null, returns its hash code. Otherwise, returns 0.

static int	Objects.hash(Object... values)

Generates hash code for the sequence of values. The values can contain nulls.

static int	Objects.equals(Object a, Object b)

Compares two values in null-safe way. If both are not null, calls equals method on first argument. If both are null, returns true. Otherwise, returns false.

With the first method we can simplify the hashCode method to:

public int hashCode() {
    int result = name.hashCode();
    result += 3 * Objects.hashCode(value);
    return result;
}

and with the second we can reduce the body of the method to single line:

public int hashCode() {
    return Objects.hash(name, value);
}

We can do the similar thing for equals:

public boolean equals(Object obj) {
   if (obj == null) {
       return false;
   }
   if (getClass() != obj.getClass()) {
       return false;
   }
   final Mapping other = (Mapping) obj;
   return Objects.equals(name, other.name)
        && Objects.equals(value, other.value);
}

Most of the conditional code is removed. Isn’t it simpler?

Other

There are two additional methods in Objects class.

static boolean	Objects.deepEquals(Object a, Object b)

If both arguments are arrays, behaves like Arrays.deepEquals(). If both arguments are null, returns true. If one argument is null, returns false. Otherwise, calls equals on the first argument.

static <T> int	Objects.compare(T a, T b, Comparator c)

If both arguments are null or both are the same reference, returns 0. Otherwise, compares the arguments using provided comparator.

Conclusion

This class is a nice addition to Java 7 and reduces some unnecessary boilerplate. New versions of IDE can even use this class to generate simpler and more concise hashCode and equals methods than before.

We can go even further and generate these methods (and more) “on-the-fly” using lombok. But it is a topic for separate post.

Advertisements

About Robert Piasecki

Husband and father, Java software developer, Linux and open-source fan.
This entry was posted in Java and tagged . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s