Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the benefit of using ComparisonChain over Objects.equal() && Objects.equal() ... with Guava

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())

like image 894
NimChimpsky Avatar asked Aug 04 '11 13:08

NimChimpsky


4 Answers

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

like image 170
Guido Medina Avatar answered Nov 15 '22 23:11

Guido Medina


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.

like image 20
SLaks Avatar answered Nov 16 '22 00:11

SLaks


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.)

like image 40
Louis Wasserman Avatar answered Nov 16 '22 00:11

Louis Wasserman


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 mentioned
  • Object.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();
    }
    
like image 30
Ray Avatar answered Nov 16 '22 00:11

Ray