First round of java.util.Objects for code review (bug 6797535)

Joe Darcy Joe.Darcy at Sun.COM
Fri Oct 9 01:21:52 UTC 2009


Hello.

Joshua Bloch wrote:
> Joe,
>
> Hi.  I think it's great that you're doing this.  A few comments:
>
>
>     +public class Objects {
>     +    private Objects() {
>     +        throw new AssertionError("No java.util.Objects instances
>     for you!");
>     +    }
>
> Cute!
>  
>
>     +
>     +    /**
>     +     * Returns {@code true} if the arguments are equal to each other
>     +     * and {@code false} otherwise.
>     +     * Consequently, if both arguments are {@code null}, {@code true}
>     +     * is returned and if exactly one argument is {@code null},
>     {@code
>     +     * false} is returned.  Otherwise, equality is determined by
>     using
>     +     * the {@link Object#equals equals} method of the first
>     +     * argument.
>     +     *
>     +     * @return {@code true} if the arguments are equal to each other
>     +     * and {@code false} otherwise
>     +     * @see Object#equals(Object)
>     +     */
>     +    public static boolean equals(Object a, Object b) {
>     +        return (a == b) || (a != null && a.equals(b));
>     +    }
>
> Very useful!  We've needed this one  ( equals(Object a, Object b) ) 
> for years.

Indeed.

>
>     +
>     +    /**
>     +     * Returns the hash code of a non-{@code null} argument and 0 for
>     +     * a {@code null} argument.
>     +     *
>     +     * @return the hash code of a non-{@code null} argument and 0 for
>     +     * a {@code null} argument
>     +     * @see Object#hashCode
>     +     */
>     +    public static int hashCode(Object o) {
>     +        return o != null ? o.hashCode() : 0;
>     +    }
>
>
> Again, very useful.  Along these lines, I would add this method too:
>
>     /**
>      * Generates a hash code for a sequence of input values. The hash 
> code is
>      * generated as if all the input values were placed into an array, 
> and that
>      * array were hashed by calling {@link Arrays#hashCode(Object[])}.
>      * <p/>
>      * <p>This method is useful for implementing {@link 
> Object#hashCode()} on
>      * objects containing multiple fields. For example, if an object 
> that has
>      * three  fields, {@code x}, {@code y}, and {@code z}, one could 
> write:
>      * <pre>
>      * @Override public int hashCode() {
>      *     return Objects.hashCode(x, y, z);
>      * }
>      * </pre>
>      * <b>Warning: When a single object reference is supplied, the 
> returned
>      * value does not equal the hash code of that object 
> reference.</b> This
>      * value can be computed by calling {@link #hashCode(Object)}.
>      */
>     public static int hash(Object... components) {
>         return Arrays.hashCode(components);
>     }

>
> People still don't know how to hash objects with multiple fields; this 
> little method makes it much easier.

Hmm.  I split up a number of the follow-up ideas into separate email
threads on core-libs-deve; one of those was whether or not some of the
existing methods in Arrays should be var-argified.

What about introducing a java.util.Hash (Hasher?) class with

* hash methods for double and long implementing the Long and Double hash
code algorithms, etc.
* the hash convenience method above

>  
>
>     +
>     +    /**
>     +     * Returns the result of calling {@code toString} for a
>     non-{@code
>     +     * null} argument and {@code "null"} for a {@code null} argument.
>     +     *
>     +     * @return the result of calling {@code toString} for a
>     non-{@code
>     +     * null} argument and {@code "null"} for a {@code null} argument
>     +     * @see Object#toString
>     +     * @see String#valueOf(Object)
>     +     */
>     +    public static String toString(Object o) {
>     +        return String.valueOf(o);
>     +    }
>
> I would definitely /not/ add this method  (Objects.toString).  It 
> brings nothing to the table that isn't already there.  People know and 
> use String.valueOf.  Let's not muddy the waters by adding another choice.

So noted.

>  
>
>     +
>     +    /**
>     +     * Returns 0 if the arguments are identical and {@code
>     +     * c.compare(a, b)} otherwise.
>     +     * Consequently, if both arguments are {@code null} 0
>     +     * is returned.
>     +     *
>     +     * <p>Note that if one of the arguments is {@code null}, a {@code
>     +     * NullPointerException} may or may not be thrown depending on
>     +     * what ordering policy, if any, the {@link Comparator
>     Comparator}
>     +     * chooses to have for {@code null} values.
>     +     *
>     +     * @return 0 if the arguments are identical and {@code
>     +     * c.compare(a, b)} otherwise.
>     +     * @see Comparable
>     +     * @see Comparator
>     +     */
>     +    public static <T> int compare(T a, T b, Comparator<? super T>
>     c) {
>     +        return (a == b) ? 0 :  c.compare(a, b);
>     +    }
>     +}
>
> I don't think you should add this method ( compare(T a, T b, 
> Comparator<? super T> c)).  Its utility is unclear, and it doesn't 
> have the power-to-weight ratio of the other methods in this class.

Yeah, I included this with "Item 12: Consider implementing Comparable"
from EJv2 in mind.

>
> I strongly suggest that you do add these two methods:
>
>     /**
>      * Checks that the specified object reference is not {@code null}. 
> This
>      * method is designed primarily for doing parameter validation in 
> methods
>      * and constructors, as demonstrated below:
>      * <pre>
>      * public Foo(Bar bar) {
>      *     this.bar = Objects.nonNull(bar);
>      * }
>      * </pre>
>      *
>      * @param obj the object reference to check for nullity
>      * @return {@code obj} if not {@code null}
>      * @throws NullPointerException if {@code obj} is {@code null}
>      */
>     public static <T> T nonNull(T obj) {
>         if (obj == null)
>             throw new NullPointerException();
>         return obj;
>     }
>
>     /**
>      * Checks that the specified object reference is not {@code null} and
>      * throws a customized {@Link NullPointerException} if it is. This 
> method
>      * is designed primarily for doing parameter validation in methods and
>      * constructors with multiple parameters, as demonstrated below:
>      * <pre>
>      * public Foo(Bar bar, Baz baz) {
>      *     this.bar = Objects.nonNull(bar, "bar must not be null");
>      *     this.baz = Objects.nonNull(baz, "baz must not be null");
>      * }
>      * </pre>
>      *
>      * @param obj     the object reference to check for nullity
>      * @param message detail message to be used in the event that a {@code
>      *                NullPointerException} is thrown
>      * @return {@code obj} if not {@code null}
>      * @throws NullPointerException if {@code obj} is {@code null}
>      */
>     public static <T> T nonNull(T obj, String message) {
>         if (obj == null)
>             throw new NullPointerException(message);
>         return obj;
>     }
>
> They do a great job reducing the verbiage in validity-checking of 
> arguments that must not be null.

I've filed bug 6889858 "Add nonNull methods to java.util.Objects" for
these last two methods.  If you want to finish off the engineering need 
for a changeset, some light tests, etc., I'll file the Sun-internal 
paperwork for these.

Once the Mercurial repos are feeling healthy again, I'm going to push
the four-method version of j.u.Objects (equals(Object, Object),
hashCode(Object), toString(Object), compare(T, T))  into JDK 7 TL.
Afterward I expect discussions of refinements, changes, and additions to
j.u.Objects to continue on the mailing list.

-Joe




More information about the core-libs-dev mailing list