Use Objects.hash() or own hashCode() implementation?

前端 未结 5 1538
清酒与你
清酒与你 2021-01-01 08:24

I have recently discovered the Objects.hash() method.

My first thought was, that this tidies up your hashCode() implementation a lot. See the following

相关标签:
5条回答
  • 2021-01-01 09:00

    Personally I'd side with the short code first, because it is so much quicker to read, change and verify as correct, which all serve to avoid bugs when modifying the class.

    Then for performance-critical classes or where fields are costly to hash, I would cache the result (like String does):

    // volatile not required for 32-bit sized primitives
    private int hash;
    
    @Override
    public final int hashCode() {
        // "Racy Single-check idiom" (Item 71, Effective Java 2nd ed.)
        int h = hash;
        if (h == 0) {
            h = Objects.hash(id, timestamp, severity, thread, classPath, message);
            hash = h;
        }
        return h;
    }
    

    In this lockless-threadsafe pattern (which assumes an immutable class, naturally) there's a slim chance that hash might get initialised by different threads multiple times, but this does not matter because the result of the public method is always identical. The key to (memory-visibility) correctness is ensuring that hash is never written and read more than once in the method.

    The array-construction penalty of Objects.hash might be lower than you imagine once the code gets JIT-inlined & optimised by the C2 compiler. Fortunately the good JDK folks have something baking that should essentially eliminate all the overheads of using it: JEP 348: Java Compiler Intrinsics for JDK APIs

    0 讨论(0)
  • 2021-01-01 09:07

    Note that the parameter of Objects.hash is Object.... This has two main consequences:

    • Primitive values used in the hash code calculation have to be boxed, e.g. this.id is converted from long to Long.
    • An Object[] has to be created to invoke the method.

    The cost of creating of these "unnecessary" objects may add up if hashCode is called frequently.

    0 讨论(0)
  • 2021-01-01 09:08

    Following is implementation of Objects.hash - which is calling Arrays.hashCode internally.

    public static int hash(Object... values) {
        return Arrays.hashCode(values);
    }
    

    This is implementation of Arrays.hashCode method

    public static int hashCode(Object a[]) {
        if (a == null)
            return 0;
    
        int result = 1;
    
        for (Object element : a)
            result = 31 * result + (element == null ? 0 : element.hashCode());
    
        return result;
    }
    

    So I agree with @Andy The cost of creating of these "unnecessary" objects may add up if hashCode is called frequently. If you are implementing yourself it would be faster.

    0 讨论(0)
  • 2021-01-01 09:08

    I would like to try and make a strong argument for both.

    Opening disclaimer

    For this answer, Objects.hash(), Objects.hashCode(), and any function provided by any library that performs this role are interchangeable. First, I would like to argue, use Objects.hash() or don't use the static Objects functions at all. Any argument for or against this method requires making assumptions about the compiled code that are not guaranteed to be true. (For example, the compiler optimizer may convert the function call into an inline call, thus bypassing the extra call stack and object allocation. Just like how loops that do nothing useful don't make it to the compiled version (unless you turn off the optimizer). You also have no guarantee that future Java versions won't include the JVM version like C# does in it's version of this method. (for security reasons I believe)) So the only safe argument you can make regarding using this function, is that it is generally safer to leave the details of a proper hash to this function than to try to implement your own naive version.

    For Objects.hash

    • Guaranteed to be a good hash.
    • Takes 5 seconds to implement.
    • Yours would have had a bug in it (somehow especially if you copy-pasted the implementation)

    Against Objects.hash

    • The Java docs make no promises about hash cross-compatibility (Will a JVM v6 and JVM v8 give the same values? always? across OS?)
    • The thing about hashCodes, They work best if "evenly distributed". So if an int value is only valid for range 1 to 100, you might want to "redistribute" its hash-codes to not all be part of the same bucket.
    • If you have any requirement that makes you question how Objects.hash works, reliability/performance wise, Think carefully if the hash-code is really what you want, and implement a custom hash-coding method that addresses your needs.
    0 讨论(0)
  • 2021-01-01 09:10

    Joshua Bloch in his book Effective Java, 3rd edition, p. 53 discourages usage of Objects.hash(...) if performance is critical.

    Primitives are being autoboxed and there is a penalty of creating an Object array.

    0 讨论(0)
提交回复
热议问题