BigDecimal equals() versus compareTo()
The answer is in the JavaDoc of the equals()
method:
Unlike
compareTo
, this method considers twoBigDecimal
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 Integer
and Double
.
From the documentation of compareTo
:
Compares this
BigDecimal
with the specifiedBigDecimal
.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 specifiedObject
for equality. UnlikecompareTo
, this method considers twoBigDecimal
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
Running Multiple Launch Configurations at Once
Detecting Collision of Two Sprites That Can Rotate
How to Build Sources Jar with Gradle
How to Properly Express Jpql "Join Fetch" with "Where" Clause as JPA 2 Criteriaquery
Getting Java.Lang.Classnotfoundexception: Org.Apache.Commons.Logging.Logfactory Exception
Java, Simplified Check If Int Array Contains Int
Measure Execution Time for a Java Method
How to Initialize an Arraylist with All Zeroes in Java
What Is the Main-Stream Java Alternative to ASP.NET/Php
How to Specify a Byte Literal in Java
Create a New Line in Java's Filewriter
Why Jscrollpane in Joptionpane Not Showing All Its Content
Java Synchronized Block for .Class
Combine Multiple Collections into a Single Logical Collection
Choose Between Executorservice's Submit and Executorservice's Execute