JDK-6891113 : More methods for java.util.Objects: deepEquals, hash, toString with default
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util
  • Affected Version: 5.0,7
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic,linux
  • CPU: generic,x86
  • Submitted: 2009-10-13
  • Updated: 2017-05-16
  • Resolved: 2009-11-24
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7
7 b77Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Description
Further discussion on the corelibs mailing list about utility methods suitable for java.util.Objects revealed several worthwhile additions including:

static toString(Object o, String default): toString taking a default if o is null
static deepEquals(Object a, Object b): run deep equals on arbritrary arguments
static hash(Object... objs): compute a hash code for inputs

Comments
SUGGESTED FIX # HG changeset patch # User darcy # Date 1256321897 25200 # Node ID 80102c165e09e45aa3814e3db5aac20ae2ecbdf6 # Parent 93f8d9494e054ee095119ad2dd16d06d76b6fde8 6891113: More methods for java.util.Objects: deepEquals, hash, toString with default Reviewed-by: alanb, gafter --- a/src/share/classes/java/util/Arrays.java Thu Oct 22 15:44:42 2009 +0100 +++ b/src/share/classes/java/util/Arrays.java Fri Oct 23 11:18:17 2009 -0700 @@ -3928,6 +3928,7 @@ public class Arrays { * @param a2 the other array to be tested for equality * @return <tt>true</tt> if the two arrays are equal * @see #equals(Object[],Object[]) + * @see Objects#deepEquals(Object, Object) * @since 1.5 */ public static boolean deepEquals(Object[] a1, Object[] a2) { @@ -3949,32 +3950,38 @@ public class Arrays { return false; // Figure out whether the two elements are equal - boolean eq; - if (e1 instanceof Object[] && e2 instanceof Object[]) - eq = deepEquals ((Object[]) e1, (Object[]) e2); - else if (e1 instanceof byte[] && e2 instanceof byte[]) - eq = equals((byte[]) e1, (byte[]) e2); - else if (e1 instanceof short[] && e2 instanceof short[]) - eq = equals((short[]) e1, (short[]) e2); - else if (e1 instanceof int[] && e2 instanceof int[]) - eq = equals((int[]) e1, (int[]) e2); - else if (e1 instanceof long[] && e2 instanceof long[]) - eq = equals((long[]) e1, (long[]) e2); - else if (e1 instanceof char[] && e2 instanceof char[]) - eq = equals((char[]) e1, (char[]) e2); - else if (e1 instanceof float[] && e2 instanceof float[]) - eq = equals((float[]) e1, (float[]) e2); - else if (e1 instanceof double[] && e2 instanceof double[]) - eq = equals((double[]) e1, (double[]) e2); - else if (e1 instanceof boolean[] && e2 instanceof boolean[]) - eq = equals((boolean[]) e1, (boolean[]) e2); - else - eq = e1.equals(e2); + boolean eq = deepEquals0(e1, e2); if (!eq) return false; } return true; + } + + static boolean deepEquals0(Object e1, Object e2) { + assert e1 != null; + boolean eq; + if (e1 instanceof Object[] && e2 instanceof Object[]) + eq = deepEquals ((Object[]) e1, (Object[]) e2); + else if (e1 instanceof byte[] && e2 instanceof byte[]) + eq = equals((byte[]) e1, (byte[]) e2); + else if (e1 instanceof short[] && e2 instanceof short[]) + eq = equals((short[]) e1, (short[]) e2); + else if (e1 instanceof int[] && e2 instanceof int[]) + eq = equals((int[]) e1, (int[]) e2); + else if (e1 instanceof long[] && e2 instanceof long[]) + eq = equals((long[]) e1, (long[]) e2); + else if (e1 instanceof char[] && e2 instanceof char[]) + eq = equals((char[]) e1, (char[]) e2); + else if (e1 instanceof float[] && e2 instanceof float[]) + eq = equals((float[]) e1, (float[]) e2); + else if (e1 instanceof double[] && e2 instanceof double[]) + eq = equals((double[]) e1, (double[]) e2); + else if (e1 instanceof boolean[] && e2 instanceof boolean[]) + eq = equals((boolean[]) e1, (boolean[]) e2); + else + eq = e1.equals(e2); + return eq; } /** --- a/src/share/classes/java/util/Objects.java Thu Oct 22 15:44:42 2009 +0100 +++ b/src/share/classes/java/util/Objects.java Fri Oct 23 11:18:17 2009 -0700 @@ -33,7 +33,7 @@ package java.util; * * @since 1.7 */ -public class Objects { +public final class Objects { private Objects() { throw new AssertionError("No java.util.Objects instances for you!"); } @@ -57,6 +57,32 @@ public class Objects { return (a == b) || (a != null && a.equals(b)); } + /** + * Returns {@code true} if the arguments are deeply equal to each other + * and {@code false} otherwise. + * + * Two {@code null} values are deeply equal. If both arguments are + * arrays, the algorithm in {@link Arrays#deepEquals(Object[], + * Object[]) Arrays.deepEquals} is used to determine equality. + * Otherwise, equality is determined by using the {@link + * Object#equals equals} method of the first argument. + * + * @param a an object + * @param b an object to be compared with {@code a} for deep equality + * @return {@code true} if the arguments are deeply equal to each other + * and {@code false} otherwise + * @see Arrays#deepEquals(Object[], Object[]) + * @see Objects#equals(Object, Object) + */ + public static boolean deepEquals(Object a, Object b) { + if (a == b) + return true; + else if (a == null || b == null) + return false; + else + return Arrays.deepEquals0(a, b); + } + /** * Returns the hash code of a non-{@code null} argument and 0 for * a {@code null} argument. @@ -68,6 +94,36 @@ public class Objects { */ public static int hashCode(Object o) { return o != null ? o.hashCode() : 0; + } + + /** + * 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>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: + * + * <blockquote><pre> + * &#064;Override public int hashCode() { + * return Objects.hash(x, y, z); + * } + * </pre></blockquote> + * + * <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)}. + * + * @param values the values to be hashed + * @return a hash value of the sequence of input values + * @see Arrays#hashCode + * @see List#hashCode + */ + public static int hash(Object... values) { + return Arrays.hashCode(values); } /** @@ -82,6 +138,23 @@ public class Objects { */ public static String toString(Object o) { return String.valueOf(o); + } + + /** + * Returns the result of calling {@code toString} on the first + * argument if the first argument is not {@code null} and returns + * the second argument otherwise. + * + * @param o an object + * @param nullDefault string to return if the first argument is + * {@code null} + * @return the result of calling {@code toString} on the first + * argument if it is not {@code null} and the second argument + * otherwise. + * @see Objects#toString(Object) + */ + public static String toString(Object o, String nullDefault) { + return (o != null) ? o.toString() : nullDefault; } /** --- a/test/java/util/Objects/BasicObjectsTest.java Thu Oct 22 15:44:42 2009 +0100 +++ b/test/java/util/Objects/BasicObjectsTest.java Fri Oct 23 11:18:17 2009 -0700 @@ -23,7 +23,7 @@ /* * @test - * @bug 6797535 + * @bug 6797535 6889858 6891113 * @summary Basic tests for methods in java.util.Objects * @author Joseph D. Darcy */ @@ -34,8 +34,11 @@ public class BasicObjectsTest { public static void main(String... args) { int errors = 0; errors += testEquals(); + errors += testDeepEquals(); errors += testHashCode(); + errors += testHash(); errors += testToString(); + errors += testToString2(); errors += testCompare(); errors += testNonNull(); if (errors > 0 ) @@ -60,6 +63,36 @@ public class BasicObjectsTest { return errors; } + private static int testDeepEquals() { + int errors = 0; + Object[] values = {null, + null, // Change to values later + new byte[] {(byte)1}, + new short[] {(short)1}, + new int[] {1}, + new long[] {1L}, + new char[] {(char)1}, + new float[] {1.0f}, + new double[]{1.0d}, + new String[]{"one"}}; + values[1] = values; + + for(int i = 0; i < values.length; i++) + for(int j = 0; j < values.length; j++) { + boolean expected = (i == j); + Object a = values[i]; + Object b = values[j]; + boolean result = Objects.deepEquals(a, b); + if (result != expected) { + errors++; + System.err.printf("When equating %s to %s, got %b instead of %b%n.", + a, b, result, expected); + } + } + + return errors; + } + private static int testHashCode() { int errors = 0; errors += (Objects.hashCode(null) == 0 ) ? 0 : 1; @@ -68,11 +101,32 @@ public class BasicObjectsTest { return errors; } + private static int testHash() { + int errors = 0; + + Object[] data = new String[]{"perfect", "ham", "THC"}; + + errors += ((Objects.hash((Object[])null) == 0) ? 0 : 1); + + errors += (Objects.hash("perfect", "ham", "THC") == + Arrays.hashCode(data)) ? 0 : 1; + + return errors; + } + private static int testToString() { int errors = 0; errors += ("null".equals(Objects.toString(null)) ) ? 0 : 1; String s = "Some string"; errors += (s.equals(Objects.toString(s)) ) ? 0 : 1; + return errors; + } + + private static int testToString2() { + int errors = 0; + String s = "not the default"; + errors += (s.equals(Objects.toString(null, s)) ) ? 0 : 1; + errors += (s.equals(Objects.toString(s, "another string")) ) ? 0 : 1; return errors; }
2009-10-23

PUBLIC COMMENTS See http://hg.openjdk.java.net/jdk7/tl/jdk/rev/80102c165e09
2009-10-23

EVALUATION A fine idea.
2009-10-13