16

I was wondering what are key differences between Guava vs Apache Commons with respect to equals and hashCode builders.

equals:

Apache Commons:

public boolean equals(Object obj) {
    if (obj == null) { return false; }
    if (obj == this) { return true; }
    if (obj.getClass() != getClass()) { return false; }
    MyClass other = (MyClass) obj;
    return new EqualsBuilder()
            .appendSuper(super.equals(obj))
            .append(field1, other.field1)
            .append(field2, other.field2)
            .isEquals();
}

Guava:

public boolean equals(Object obj) {
    if (obj == null) { return false; }
    if (obj == this) { return true; }
    if (obj.getClass() != getClass()) { return false; }
    MyClass other = (MyClass) obj;
    return Objects.equal(this.field1, other.field1)
            && Objects.equal(this.field1, other.field1);
}

hashCode:

Apache Commons:

public int hashCode() {
    return new HashCodeBuilder(17, 37)
            .append(field1)
            .append(field2)
            .toHashCode();
}

Guava:

public int hashCode() {
    return Objects.hashCode(field1, field2);
}

One of the key difference appears to be improved code readability with Guava's version.

I couldn't find more information from https://code.google.com/p/guava-libraries/wiki/CommonObjectUtilitiesExplained. It would be useful to know more differences (especially any performance improvement?) if there are any.

Freek de Bruijn
  • 3,552
  • 2
  • 22
  • 28
Abhishek
  • 323
  • 1
  • 3
  • 8
  • Apache's creates a temporary object, but on the plus side it also supports reflectively building for quick prototype code. – Ben Manes Jun 25 '15 at 20:30
  • Correct. Thanks, Ben. – Abhishek Jun 26 '15 at 09:22
  • Also consider something like [`AutoValue`](https://github.com/google/auto/tree/master/value) for value objects to get your `equals`/`hashCode`/`toString` etc. generated for you. – ColinD Jun 26 '15 at 18:11
  • Related: Java 7 includes [Objects.equals](https://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#equals(java.lang.Object,%20java.lang.Object)) and [Objects.hash](https://docs.oracle.com/javase/7/docs/api/java/util/Objects.html#hash(java.lang.Object...)) which work like Guava's – laffuste Feb 07 '18 at 08:47
  • 1
    With all the readability, the author of the OP still made the mistake to compare field1 twice and forgot about field2 (guava equals). With a plain implementation, there would be alarms by static code analyzers... – Daniel Alder Mar 12 '19 at 15:26

2 Answers2

24

I'd call this difference "existence". There are EqualsBuilder and HashCodeBuilder in Apache Commons and there are no builders in Guava. All you get from Guava is a utility class MoreObjects (renamed from Objects as there's such a class in JDK now).

The advantages of Guava's approach come from the non-existence of the builder:

  • it produces no garbage
  • it's faster

The JIT compiler can possibly eliminate the garbage via Escape Analysis and also the associated overhead. Then they get equally fast as they do exactly the same.

I personally find the builders slightly more readable. If you find not using them better, then Guava is surely the right thing for you. As you can see, the static methods are good enough for the task.

Note also that there's also a ComparisonChain which is a sort of Comparable-builder.

Aldo
  • 536
  • 5
  • 23
maaartinus
  • 44,714
  • 32
  • 161
  • 320
  • 1
    `Objects.hashCode` will allocate for varargs or and potentially for autoboxing of course. Also note that `ComparisonChain` looks like a builder but doesn't actually allocate anything. – ColinD Jun 26 '15 at 18:13
  • I wonder how long it takes Hotspot to optimise this, because I just redid my microbenchmark and it's still fastest to implement hashCode inline, not significantly slower to use HashCodeBuilder, but 20 times slower to use Objects.hash(...). In the worst case scenario where everything you're hashing is ints. – Hakanai Apr 27 '17 at 00:24
0

Under the hood Guava uses Arrays.hashCode(). Varagrs impose performance penalty and there is potential for autoboxing, which again would impose performance hit. According to Java's documentation

If the array contains other arrays as elements, the hash code is based on their identities rather than their contents

Alternative to Objects.hasCode might be Objects.deepHashCode but it's not employed by Guava. And it has a drawback in case of circular references

It is therefore unacceptable to invoke this method on an array that contains itself as an element

Normally Apache Commons works more like deepHashCode, but might add reflection to the picture and tackle all the aforementioned issues, but (arguably) can suffer from much worse performance.

Form design perspective Apache Commons implements rules laid out by Effective Java items 10 and 11. Which adds a very different feel to it