When equals() is not equal enough

The other day we were struggling doing comparisions with BigDecimals in a distributed application with BigDecimals originating from different sources. As we had learned we used equals() to compare the objects and even though everything seemed correct, even in the debugger, the logic that indicated an equality condition never was executed.

Check these two methods, and try to predict the outcome:

  private void sample1() {
    BigDecimal one1 = new BigDecimal("1");
    BigDecimal one2 = new BigDecimal("1.000");

    System.out.println("Comparing new BigDecimal(\"1\") and BigDecimal(\"1.000\"):");
    if (one1.equals(one2)) {
      System.out.println("  equals() indicates equality...");
    } else {
      System.out.println("  equals() indicates different values...");
      if (one1.compareTo(one2) == 0) {
        System.out.println("    but comparesTo() thinks the two BigDecimals are equal.");
      } else {
        System.out.println("    and comparesTo() thinks the same.");
      }
    }
  }

  private void sample2() {
    BigDecimal one1 = new BigDecimal(1);
    BigDecimal one2 = one1.setScale(3);

    System.out.println("Comparing new BigDecimal(1) and BigDecimal(1).setScale(3):");
    if (one1.equals(one2)) {
      System.out.println("  equals() indicates equality...");
    } else {
      System.out.println("  equals() indicates different values...");
      if (one1.compareTo(one2) == 0) {
        System.out.println("    but comparesTo() thinks the two BigDecimals are equal.");
      } else {
        System.out.println("    and comparesTo() thinks the same.");
      }
    }
  }

Looking into the Javadoc (Java 5) of BigDecimals gave a first hints:

Note: care should be exercised if BigDecimal objects are used as keys in a SortedMap or elements in a SortedSet since BigDecimal’s natural ordering is inconsistent with equals. See Comparable, SortedMap or SortedSet for more information.

and

Compares this BigDecimal with the specified Object for equality. Unlike compareTo, this method considers two BigDecimal objects equal only if they are equal in value and scale (thus 2.0 is not equal to 2.00 when compared by this method).

That definitely was a bit unexpected, but at least documented.

Advertisements