Bigdecimal Equals() Versus Compareto()

BigDecimal equals() versus compareTo()

The answer is in the JavaDoc of the equals() method:

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

In other words: equals() checks if the BigDecimal objects are exactly the same in every aspect. compareTo() "only" compares their numeric value.

As to why equals() behaves this way, this has been answered in this SO question.

Why is BigDecimal.equals specified to compare both value and scale individually?

Because in some situations, an indication of precision (i.e. the margin of error) may be important.

For example, if you're storing measurements made by two physical sensors, perhaps one is 10x more precise than the other. It may be important to represent this fact.

equals and compare with BigDecimal

The first line is just an optimization meant to early return a result if both references point to the same object.

Is price nullable? I assume it is, as you're checking for it within your equals() implementation. In that case your code won't work in case other.price will be null. Specifically this code here:

price.compareTo(other.price) != 0

Will throw a NullPointerException.

You can fix it like this:

    @Override
public boolean equals(Object obj) {

if (this == obj) return true; // is this right or should this be deleted

if (obj == null || getClass() != obj.getClass()) return false;

final MyProduct other = (MyProduct) obj;

// If you prefer, the below two can be replaced with a single condition
// price != null ^ other.price != null
// Credits to @Andreas
if (price == null && other.price != null) {
return false;
}
if (price != null && other.price == null) {
return false;
}
if (other.price != null && price.compareTo(other.price) != 0) {
return false;
}

return super.equals(obj);
}

Now, you could probably make it shorter, but personally I find it the most readable this way.

Anyways, unless you really, really care about customising your equals() implementation, I would suggest generating one with your IDE and sticking to it. They do a decent job most of the time and you don't have to worry about it being broken (although comparing BigDecimals may be tricky for them, given you don't care about the scale but rather just the value).

Comparing BigDecimal

You need to use the String constructor to get the correct scales, because the BigDecimal(double) will get the small scale possible

translates a double into a BigDecimal which is the exact decimal representation of the double's binary floating-point value. The scale of the returned BigDecimal is the smallest value such that (10scale × val) is an integer.

More precision about the documentations :

BigDecimal.equals(Object)

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

BigDecimal.compareTo(BigDecimal)

Compares this BigDecimal with the specified BigDecimal. Two BigDecimal objects that are equal in value but have a different scale (like 2.0 and 2.00) are considered equal by this method. This method is provided in preference to individual methods for each of the six boolean comparison operators (<, ==, >, >=, !=, <=). The suggested idiom for performing these comparisons is: (x.compareTo(y) 0), where is one of the six comparison operators.

You will find that the equals use the scale for the comparison, giving some "strange" result.

BigDecimal bd1 = new BigDecimal("2"); //scale 0
BigDecimal bd2 = new BigDecimal("2.00"); //scale 2

bd1.equals(bd2); //false
bd1.compareTo(bd2); //0 => which means equivalent

How to use comparison operators like , =, on BigDecimal

Every object of the Class BigDecimal has a method compareTo you can use to compare it to another BigDecimal. The result of compareTo is then compared > 0, == 0 or < 0 depending on what you need. Read the documentation and you will find out.

The operators ==, <, > and so on can only be used on primitive data types like int, long, double or their wrapper classes like Integerand Double.

From the documentation of compareTo:

Compares this BigDecimal with the specified BigDecimal.

Two BigDecimal
objects that are equal in value but have a different scale (like 2.0
and 2.00) are considered equal by this method. This method is provided
in preference to individual methods for each of the six boolean
comparison operators (<, ==, >, >=, !=, <=). The suggested idiom for
performing these comparisons is: (x.compareTo(y) <op> 0), where <op>
is one of the six comparison operators.

Returns:
-1, 0, or 1 as this BigDecimal is numerically less than, equal to, or greater than val.

BigDecimal equals = and = best practice

if(val.compareTo(new BigDecimal(11)) <= 0) //val <=11
if(val.compareTo(new BigDecimal(11)) >= 0) //val >=11

Why BigDecimal(5.50) not equals to BigDecimal(5.5) and how to work around this issue?

From the javadoc of BigDecimal

equals

public boolean equals(Object x)

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

Simply use compareTo() == 0

BigDecimal#compareTo with different scales

new BigDecimal(0.82) is not actually 0.82, because you're passing a double value -- the double closest to 0.82, which is not exactly 0.82 -- to the constructor, so new BigDecimal(0.82) is a BigDecimal equal to the double closest to 0.82.

Instead, use new BigDecimal("0.82").



Related Topics



Leave a reply



Submit