281

I have the following code in Java;

BigDecimal price; // assigned elsewhere

if (price.compareTo(new BigDecimal("0.00")) == 0) {
    return true;
}

What is the best way to write the if condition?

Bohemian
  • 412,405
  • 93
  • 575
  • 722
JoJo
  • 4,643
  • 9
  • 42
  • 65
  • 19
    Many answers are suggesting using BigDecimal's .equals() method. But that method takes scale into consideration, so is not equivalent to using compareTo(). – GriffeyDog Jun 08 '12 at 15:09

13 Answers13

648

Use compareTo(BigDecimal.ZERO) instead of equals():

if (price.compareTo(BigDecimal.ZERO) == 0) // see below

Comparing with the BigDecimal constant BigDecimal.ZERO avoids having to construct a new BigDecimal(0) every execution.

FYI, BigDecimal also has constants BigDecimal.ONE and BigDecimal.TEN for your convenience.


Note!

The reason you can't use BigDecimal#equals() is that it takes scale into consideration:

new BigDecimal("0").equals(BigDecimal.ZERO) // true
new BigDecimal("0.00").equals(BigDecimal.ZERO) // false!

so it's unsuitable for a purely numeric comparison. However, BigDecimal.compareTo() doesn't consider scale when comparing:

new BigDecimal("0").compareTo(BigDecimal.ZERO) == 0 // true
new BigDecimal("0.00").compareTo(BigDecimal.ZERO) == 0 // true
Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • 16
    BigDecimal.ZERO.compareTo(price) == 0 – Jackkobec Jan 27 '20 at 14:53
  • 2
    Is there any particular reason for this implementation of BigDecimal - "new BigDecimal("0.00").equals(BigDecimal.ZERO) // false!"? Why 0.00 is not scaled down to 0 with 0 scale? – Pavel Dec 03 '20 at 10:13
  • 1
    @Pavel it’s all in the [documentation](https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/math/BigDecimal.html). – Bohemian Dec 03 '20 at 17:44
  • 1
    weird! price == BigDecimal.valueOf(0.00d) is not true when the price is zero! – Mehrnoosh May 20 '21 at 10:50
  • 2
    @Mehrnoosh it never will be because in Java `==` compares object identity - ie if it’s the same object, not if the two sides have equal value. In Java, always use `.equals()` to compare things. – Bohemian May 20 '21 at 15:50
  • `The reason you can't use BigDecimal#equals() is that it takes scale into consideration` wouldn't that be precision rather than scale? – Mark W Dec 22 '21 at 14:03
  • 1
    @MarkW no, it's [scale](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigDecimal.html#scale()) – Bohemian Dec 22 '21 at 20:25
118

Alternatively, signum() can be used:

if (price.signum() == 0) {
    return true;
}
rouble
  • 16,364
  • 16
  • 107
  • 102
kman
  • 1,189
  • 1
  • 7
  • 5
  • 28
    Maybe it is faster, but compareTo(BigDecimal.ZERO) is more readable. – ElYeante Mar 06 '14 at 10:46
  • 1
    @ElYeante, you can always wrap this with method, that has more readable name, or even describes part of your business-logic, connectaed with such comparison – WeGa Apr 07 '16 at 10:53
  • 4
    Unfortuntely signum() is not null-safe, whereas compareTo is, when comparing like BigDecimal.ZERO.compareTo(), so pay attention to that – WeGa Oct 18 '16 at 08:10
  • 19
    @WeGa That's not true: `BigDecimal.ZERO.compareTo(null)` will throw NPE – ACV Apr 06 '17 at 14:16
  • 6
    @ACV, thanks for your vigilance. Looked at source code, compareTo() only expects non-null argument indeed. – WeGa Apr 10 '17 at 08:01
27

There is a constant that you can check against:

someBigDecimal.compareTo(BigDecimal.ZERO) == 0
pablochan
  • 5,625
  • 27
  • 42
10

Alternatively, I think it is worth mentioning that the behavior of equals and compareTo methods in the class BigDecimal are not consistent with each other.

This basically means that:

BigDecimal someValue = new BigDecimal("0.00");
System.out.println(someValue.compareTo(BigDecimal.ZERO) == 0); // true
System.out.println(someValue.equals(BigDecimal.ZERO)); // false

Therefore, you have to be very careful with the scale in your someValue variable, otherwise you would get unexpected results.

Edwin Dalorzo
  • 76,803
  • 25
  • 144
  • 205
5

I usually use the following:

if (selectPrice.compareTo(BigDecimal.ZERO) == 0) { ... }
gpol
  • 966
  • 2
  • 19
  • 30
5

You would want to use equals() since they are objects, and utilize the built in ZERO instance:

if (selectPrice.equals(BigDecimal.ZERO))

Note that .equals() takes scale into account, so unless selectPrice is the same scale (0) as .ZERO then this will return false.

To take scale out of the equation as it were:

if (selectPrice.compareTo(BigDecimal.ZERO) == 0)

I should note that for certain mathematical situations, 0.00 != 0, which is why I imagine .equals() takes the scale into account. 0.00 gives precision to the hundredths place, whereas 0 is not that precise. Depending on the situation you may want to stick with .equals().

Andrii Abramov
  • 10,019
  • 9
  • 74
  • 96
NominSim
  • 8,447
  • 3
  • 28
  • 38
  • 1
    Java BigDecimal's behaviour of `equals` and `compareTo` is not as you think. http://docs.oracle.com/javase/1.5.0/docs/api/java/math/BigDecimal.html#compareTo(java.math.BigDecimal) – nhahtdh Aug 31 '12 at 01:53
  • 1
    Care to explain what you mean instead of linking to the docs? What I suggested should work for the OP. – NominSim Aug 31 '12 at 02:39
  • 1
    Edwin Dalorzo's answer explains it quite well, actually. `equals` takes scale into account, which is not what we want here. – nhahtdh Aug 31 '12 at 02:42
  • 1
    @nhahtdh Thanks for the information, in fact though there are situations where `equals` *should* be used instead of `compareTo()`. The OP doesn't specify what type of mathematics he is using, so you're right it is better to give him both option. – NominSim Aug 31 '12 at 12:11
5

A simple and better way for your exemple is:

BigDecimal price;

if(BigDecimal.ZERO.compareTo(price) == 0){
    
   //Returns TRUE

}
Félix Maroy
  • 1,389
  • 2
  • 16
  • 21
4

GriffeyDog is definitely correct:

Code:

BigDecimal myBigDecimal = new BigDecimal("00000000.000000");
System.out.println("bestPriceBigDecimal=" + myBigDecimal);
System.out.println("BigDecimal.valueOf(0.000000)=" + BigDecimal.valueOf(0.000000));
System.out.println(" equals=" + myBigDecimal.equals(BigDecimal.ZERO));
System.out.println("compare=" + (0 == myBigDecimal.compareTo(BigDecimal.ZERO)));

Results:

myBigDecimal=0.000000
BigDecimal.valueOf(0.000000)=0.0
 equals=false
compare=true

While I understand the advantages of the BigDecimal compare, I would not consider it an intuitive construct (like the ==, <, >, <=, >= operators are). When you are holding a million things (ok, seven things) in your head, then anything you can reduce your cognitive load is a good thing. So I built some useful convenience functions:

public static boolean equalsZero(BigDecimal x) {
    return (0 == x.compareTo(BigDecimal.ZERO));
}
public static boolean equals(BigDecimal x, BigDecimal y) {
    return (0 == x.compareTo(y));
}
public static boolean lessThan(BigDecimal x, BigDecimal y) {
    return (-1 == x.compareTo(y));
}
public static boolean lessThanOrEquals(BigDecimal x, BigDecimal y) {
    return (x.compareTo(y) <= 0);
}
public static boolean greaterThan(BigDecimal x, BigDecimal y) {
    return (1 == x.compareTo(y));
}
public static boolean greaterThanOrEquals(BigDecimal x, BigDecimal y) {
    return (x.compareTo(y) >= 0);
}

Here is how to use them:

    System.out.println("Starting main Utils");
    BigDecimal bigDecimal0 = new BigDecimal(00000.00);
    BigDecimal bigDecimal2 = new BigDecimal(2);
    BigDecimal bigDecimal4 = new BigDecimal(4);  
    BigDecimal bigDecimal20 = new BigDecimal(2.000);
    System.out.println("Positive cases:");
    System.out.println("bigDecimal0=" + bigDecimal0 + " == zero is " + Utils.equalsZero(bigDecimal0));
    System.out.println("bigDecimal2=" + bigDecimal2 + " <  bigDecimal4=" + bigDecimal4 + " is " + Utils.lessThan(bigDecimal2, bigDecimal4));
    System.out.println("bigDecimal2=" + bigDecimal2 + " == bigDecimal20=" + bigDecimal20 + " is " + Utils.equals(bigDecimal2, bigDecimal20));
    System.out.println("bigDecimal2=" + bigDecimal2 + " <= bigDecimal20=" + bigDecimal20 + " is " + Utils.equals(bigDecimal2, bigDecimal20));
    System.out.println("bigDecimal2=" + bigDecimal2 + " <= bigDecimal4=" + bigDecimal4 + " is " + Utils.lessThanOrEquals(bigDecimal2, bigDecimal4));
    System.out.println("bigDecimal4=" + bigDecimal4 + " >  bigDecimal2=" + bigDecimal2 + " is " + Utils.greaterThan(bigDecimal4, bigDecimal2));
    System.out.println("bigDecimal4=" + bigDecimal4 + " >= bigDecimal2=" + bigDecimal2 + " is " + Utils.greaterThanOrEquals(bigDecimal4, bigDecimal2));
    System.out.println("bigDecimal2=" + bigDecimal2 + " >= bigDecimal20=" + bigDecimal20 + " is " + Utils.greaterThanOrEquals(bigDecimal2, bigDecimal20));
    System.out.println("Negative cases:");
    System.out.println("bigDecimal2=" + bigDecimal2 + " == zero is " + Utils.equalsZero(bigDecimal2));
    System.out.println("bigDecimal2=" + bigDecimal2 + " == bigDecimal4=" + bigDecimal4 + " is " + Utils.equals(bigDecimal2, bigDecimal4));
    System.out.println("bigDecimal4=" + bigDecimal4 + " <  bigDecimal2=" + bigDecimal2 + " is " + Utils.lessThan(bigDecimal4, bigDecimal2));
    System.out.println("bigDecimal4=" + bigDecimal4 + " <= bigDecimal2=" + bigDecimal2 + " is " + Utils.lessThanOrEquals(bigDecimal4, bigDecimal2));
    System.out.println("bigDecimal2=" + bigDecimal2 + " >  bigDecimal4=" + bigDecimal4 + " is " + Utils.greaterThan(bigDecimal2, bigDecimal4));
    System.out.println("bigDecimal2=" + bigDecimal2 + " >= bigDecimal4=" + bigDecimal4 + " is " + Utils.greaterThanOrEquals(bigDecimal2, bigDecimal4));

The results look like this:

Positive cases:
bigDecimal0=0 == zero is true
bigDecimal2=2 <  bigDecimal4=4 is true
bigDecimal2=2 == bigDecimal20=2 is true
bigDecimal2=2 <= bigDecimal20=2 is true
bigDecimal2=2 <= bigDecimal4=4 is true
bigDecimal4=4 >  bigDecimal2=2 is true
bigDecimal4=4 >= bigDecimal2=2 is true
bigDecimal2=2 >= bigDecimal20=2 is true
Negative cases:
bigDecimal2=2 == zero is false
bigDecimal2=2 == bigDecimal4=4 is false
bigDecimal4=4 <  bigDecimal2=2 is false
bigDecimal4=4 <= bigDecimal2=2 is false
bigDecimal2=2 >  bigDecimal4=4 is false
bigDecimal2=2 >= bigDecimal4=4 is false
Tihamer
  • 935
  • 10
  • 8
  • 2
    There are multiple answers explaining exactly that. What is the point of adding another answer? If you have additional information, then it is a good idea to add new answer, but this isn't the case in this post. – Tom May 24 '19 at 15:22
  • 1
    Point taken. However, when I'm learning something, I like to see as many examples as possible, even if they are similar. For you, Tom, I added my library that I found useful. Your milage may vary. :-) – Tihamer May 29 '19 at 14:22
0

Just want to share here some helpful extensions for kotlin

fun BigDecimal.isZero() = compareTo(BigDecimal.ZERO) == 0
fun BigDecimal.isOne() = compareTo(BigDecimal.ONE) == 0
fun BigDecimal.isTen() = compareTo(BigDecimal.TEN) == 0
Nokuap
  • 2,289
  • 2
  • 17
  • 17
0
if(price.floatValue() == 0){
   return true; //works for 0\0.0
}
barbarous
  • 31
  • 3
0

We can use java.math.BigDecimal.signum()

Returns the signum function of this BigDecimal.

Returns:-1, 0, or 1 as the value of this BigDecimalis negative, zero, or positive.

     BigDecimal price; // assigned elsewhere
    
     if (price.signum() == 0) {
         return true;
     }
ismile47
  • 531
  • 5
  • 3
-2
BigDecimal.ZERO.setScale(2).equals(new BigDecimal("0.00"));
DongHoon Kim
  • 386
  • 2
  • 14
  • 1
    While this code may answer the question, providing additional [context](https://meta.stackexchange.com/q/114762) regarding _how_ and/or _why_ it solves the problem would improve the answer's long-term value. Remember that you are answering the question for readers in the future, not just the person asking now! Please [edit](http://stackoverflow.com/posts/43273320/edit) your answer to add an explanation, and give an indication of what limitations and assumptions apply. It also doesn't hurt to mention why this answer is more appropriate than others. – Dev-iL Apr 07 '17 at 08:53
-10

There is a static constant that represents 0:

BigDecimal.ZERO.equals(selectPrice)

You should do this instead of:

selectPrice.equals(BigDecimal.ZERO)

in order to avoid the case where selectPrice is null.

tskuzzy
  • 35,812
  • 14
  • 73
  • 140
  • 3
    Java BigDecimal's behaviour of `equals` and `compareTo` is not as you think. http://docs.oracle.com/javase/1.5.0/docs/api/java/math/BigDecimal.html#compareTo(java.math.BigDecimal) – nhahtdh Aug 31 '12 at 01:53
  • so for second line...if selectedPrice is null then it will just throw NullPointerException. – user3206236 Mar 13 '19 at 11:34