I have just started using google's Guava collection (ComparisonChain and Objects). In my pojo I am overiding the equals method, so I did this first:
return ComparisonChain.start()
.compare(this.id, other.id)
.result() == 0;
However, I then realized that I could also use this :
return Objects.equal(this.id, other.id);
And I fail to see when comparison chain would be better as you can easily add further conditions like so:
return Objects.equal(this.name, other.name)
&& Objects.equal(this.number, other.number);
The only benefit I can see if you specifically need an int returned. It has two extra method calls (start and result) and is more complex to a noob.
Are there obvious benefits of ComparisonChain I missing ?
(Yes, I am also overriding hashcode with appropriate Objects.hashcode()
)
I would be careful when using Guava's ComparisonChain
because it creates an instance of it per element been compared so you would be looking at a creation of N x Log N
comparison chains just to compare if you are sorting, or N
instances if you are iterating and checking for equality.
I would instead create a static Comparator
using the newest Java 8 API if possible or Guava's Ordering
API which allows you to do that, here is an example with Java 8:
import java.util.Comparator;
import static java.util.Comparator.naturalOrder;
import static java.util.Comparator.nullsLast;
private static final Comparator<DomainObject> COMPARATOR=Comparator
.comparingInt(DomainObject::getId)
.thenComparing(DomainObject::getName,nullsLast(naturalOrder()));
@Override
public int compareTo(@NotNull DomainObject other) {
return COMPARATOR.compare(this,other);
}
Here is how to use the Guava's Ordering
API: https://github.com/google/guava/wiki/OrderingExplained
ComparisonChain
allow you to check whether an object is less-than or greater-than another object by comparing multiple properties (like sorting a grid by multiple columns).
It should be used when implementing Comparable
or Comparator
.
Objects.equal
can only check for equality.
ComparisonChain is meant to be used in helping objects implement the Comparable or Comparator interfaces.
If you're just implementing Object.equals(), then you're correct; Objects.equal is all you need. But if you're trying to implement Comparable or Comparator -- correctly -- that is much easier with ComparisonChain than otherwise.
Consider:
class Foo implements Comparable<Foo> {
final String field1;
final int field2;
final String field3;
public boolean equals(@Nullable Object o) {
if (o instanceof Foo) {
Foo other = (Foo) o;
return Objects.equal(field1, other.field1)
&& field2 == other.field2
&& Objects.equal(field3, other.field3);
}
return false;
}
public int compareTo(Foo other) {
return ComparisonChain.start()
.compare(field1, other.field1)
.compare(field2, other.field2)
.compare(field3, other.field3)
.result();
}
}
as opposed to implementing compareTo as
int result = field1.compareTo(other.field2);
if (result == 0) {
result = Ints.compare(field2, other.field2);
}
if (result == 0) {
result = field3.compareTo(other.field3);
}
return result;
...let alone the trickiness of doing that correctly, which is higher than you'd guess. (I have seen more ways to mess up compareTo than you can imagine.)
In the context of overriding methods in your POJOs, I think of a few of Guava's tools matching with a few standard methods.
Object.equals
is handled using Objects.equals
in roughly the manner you mentionedObject.hashCode
is handled with Objects.hashCode
like return Objects.hashCode(id, name);
Comparable.compareTo
is handled with ComparisonChain
as below:
public int compareTo(Chimpsky chimpsky) {
return ComparisonChain.start()
.compare(this.getId(), chimpsky.getId())
.compare(this.getName(), chimpsky.getName())
.result();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With