sunny
sunny

Reputation: 852

Guava ComparisonChain why does it not terminate after first compare returns non-zero result

Is the comparison chain in guava not supposed to evaluate the compares lazily ? In the below code the NullComparator (apache) would return a non-zero value , should the chain not terminate ?

From the docs : the ComparisonChain implementation stops calling its inputs' compareTo and compare methods as soon as one of them returns a nonzero result

    String x = null;
    String y = "y";
    ComparisonChain.start().compare(x,y, new NullComparator(false)).
            compare(x.getBytes().toString(), y.getBytes().toString()).result();

note: the above was just an example . maybe this would be the better example

ComparisonChain.start().compare(x,y, new NullComparator(false)).
        compare(x.getBytes(), y.getBytes(), UnsignedBytes.lexicographicalComparator()).result();

Upvotes: 2

Views: 1060

Answers (2)

Tavian Barnes
Tavian Barnes

Reputation: 12922

Nothing can stop Java from evaluating the arguments to compare(), even if the method does nothing. x.getBytes() will throw an NPE because x is null.

Perhaps this would work?

return Ordering.onResultOf(new Function<String, String>() {
            @Override
            public String apply(String input) {
                return input.getBytes().toString();
            }
        })
        .nullsFirst()
        .compare(x, y);

Keep in mind though that input.getBytes().toString() is likely to not make very much sense to sort by (it will look like [B@35c41b).

Upvotes: 5

NoDataFound
NoDataFound

Reputation: 11959

That's because what is lazy is the call to compare, not the call to x.getBytes(), hence the NPE ! ie:

ComparisonChain.start()
  .compare(x,y, new NullComparator(false))
  .compare(x.getBytes().toString(), y.getBytes().toString()) // <-- tries to invoke compare with two objects
  .result();

You should try with a Comparator, which like this :

ComparisonChain.start()
  .compare(x,y, new NullComparator(false))
  .compare(x, y, new Comparator<String>() {
    int compare(String a, String b) {
      return a.getBytes().toString().compareTo(b.getBytes().toString());
    }
  })
  .result();

Or with Java 8 :

ComparisonChain.start()
  .compare(x,y, new NullComparator(false))
  .compare(x, y, (a, b) -> a.getBytes().toString().compareTo(b.getBytes().toString()))
  .result();

Note that, comparing getBytes().toString() in real situations might not be a good idea...

Upvotes: 3

Related Questions