Jak sprawdzić, czy zmienna BigDecimal == 0 w Javie?

202

Mam następujący kod w Javie;

BigDecimal price; // assigned elsewhere

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

Jaki jest najlepszy sposób na napisanie warunku if?

JoJo
źródło
12
Wiele odpowiedzi sugeruje użycie metody .equals () BigDecimal. Ale ta metoda bierze pod uwagę skalę, więc nie jest równoważna z użyciem CompareTo ().
GriffeyDog,

Odpowiedzi:

472

Użyj compareTo(BigDecimal.ZERO)zamiast equals():

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

Porównanie ze BigDecimalstałą BigDecimal.ZEROpozwala uniknąć konstruowania new BigDecimal(0)każdego wykonania.

FYI, BigDecimalma również stałe BigDecimal.ONEi BigDecimal.TENdla Twojej wygody.


Uwaga!

Nie możesz używać BigDecimal#equals(), ponieważ bierze pod uwagę skalę :

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

więc nie nadaje się do czysto numerycznego porównania. Jednak BigDecimal.compareTo()nie uwzględnia skali przy porównywaniu:

new BigDecimal("0").compareTo(BigDecimal.ZERO) == 0 // true
new BigDecimal("0.00").compareTo(BigDecimal.ZERO) == 0 // true
Czeski
źródło
BigDecimal.ZERO.compareTo (cena) == 0
Jackkobec
97

Alternatywnie można użyć signum () :

if (price.signum() == 0) {
    return true;
}
kman
źródło
21
Być może jest szybszy, ale CompareTo (BigDecimal.ZERO) jest bardziej czytelny.
ElYeante,
@ElYeante, zawsze możesz zawinąć to w metodę, która ma bardziej czytelną nazwę, lub nawet opisuje część logiki biznesowej, połączoną z takim porównaniem
WeGa
3
Niestety, signum () nie jest zerowo bezpieczny, podczas gdy CompareTo jest, gdy porównujesz jak BigDecimal.ZERO.compareTo (), więc zwróć uwagę na to
WeGa 18.10.16
15
@WeGa To nieprawda: BigDecimal.ZERO.compareTo(null)rzuci NPE
ACV
5
@ACV, dziękuję za czujność. Patrząc na kod źródłowy, CompareTo () rzeczywiście oczekuje tylko argumentu innego niż null.
WeGa
24

Istnieje stała, którą możesz sprawdzić w stosunku do:

someBigDecimal.compareTo(BigDecimal.ZERO) == 0
pablochan
źródło
3
Prośba o pozwolenie na kradzież terminologii „warunek Yoda”.
SimplyPanda,
3
To jest fantastyczne .
SimplyPanda,
Zachowanie Java BigDecimal equalsi compareTonie jest takie, jak myślisz. docs.oracle.com/javase/1.5.0/docs/api/java/math/…
nhahtdh
2
BigDecimal's CompareTo nadal zgłosi wyjątek, jeśli podasz wartość null.
John Jiang
5

Zwykle używam następujących:

if (selectPrice.compareTo(BigDecimal.ZERO) == 0) { ... }
gpol
źródło
5

Alternatywnie, myślę, że warto wspomnieć, że zachowanie metod równości i metod porównywania w klasie BigDecimal nie jest ze sobą zgodne .

Zasadniczo oznacza to, że:

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

Dlatego musisz bardzo uważać na skalę w someValuezmiennej, w przeciwnym razie uzyskasz nieoczekiwany wynik.

Edwin Dalorzo
źródło
5

Chciałbyś użyć equals (), ponieważ są obiektami, i użyć wbudowanej instancji ZERO:

if(selectPrice.equals(BigDecimal.ZERO))

Zauważ, że .equals()bierze się pod uwagę skalę, więc jeśli selectPrice jest tej samej skali (0), .ZEROto wtedy zwróci false.

Aby wyjąć skalę z równania:

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

Powinienem zauważyć, że w niektórych sytuacjach matematycznych, 0.00 != 0dlatego wyobrażam sobie, że .equals()bierze pod uwagę skalę. 0.00daje precyzję setnym miejscu, a 0nie jest tak precyzyjne. W zależności od sytuacji, z którą chcesz się trzymać .equals().

NominSim
źródło
Zachowanie Java BigDecimal equalsi compareTonie jest takie, jak myślisz. docs.oracle.com/javase/1.5.0/docs/api/java/math/…
nhahtdh
Chcesz wyjaśnić, co masz na myśli, zamiast linkować do dokumentów? To, co zasugerowałem, powinno działać dla PO.
NominSim
Odpowiedź Edwina Dalorzo w rzeczywistości wyjaśnia to całkiem dobrze. equalsbierze pod uwagę skalę, której nie chcemy tutaj.
nhahtdh
@nhahtdh Dzięki za informacje, w rzeczywistości jednak istnieją sytuacje, w których equals należy użyć zamiast compareTo(). OP nie określa, jakiego rodzaju matematyki używa, więc masz rację, lepiej dać mu obie opcje.
NominSim
3

GriffeyDog jest zdecydowanie poprawny:

Kod:

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

Wyniki:

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

Chociaż rozumiem zalety porównania BigDecimal, nie uważałbym go za intuicyjną konstrukcję (podobnie jak operatory ==, <,>, <=,> =). Kiedy trzymasz w głowie milion rzeczy (ok, siedem rzeczy), wtedy wszystko, co możesz zmniejszyć obciążenie poznawcze, jest dobrą rzeczą. Zbudowałem więc kilka użytecznych funkcji:

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);
}

Oto jak z nich korzystać:

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

Wyniki wyglądają następująco:

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
źródło
1
Istnieje wiele odpowiedzi, które dokładnie to wyjaśniają. Po co dodawać kolejną odpowiedź? Jeśli masz dodatkowe informacje, dobrym pomysłem jest dodanie nowej odpowiedzi, ale w tym poście tak nie jest.
Tom
Punkt wzięty. Jednak gdy się czegoś uczę, lubię widzieć jak najwięcej przykładów, nawet jeśli są one podobne. Dla ciebie, Tom, dodałem swoją bibliotekę, którą uważam za przydatną. Twój przebieg może się różnić. :-)
Tihamer
0

Chcę tylko udostępnić tutaj kilka pomocnych rozszerzeń dla kotlin

fun BigDecimal.isZero() = compareTo(BigDecimal.ZERO) == 0
fun BigDecimal.isOne() = compareTo(BigDecimal.ONE) == 0
fun BigDecimal.isTen() = compareTo(BigDecimal.TEN) == 0
Nokuap
źródło
-2
BigDecimal.ZERO.setScale(2).equals(new BigDecimal("0.00"));
DongHoon Kim
źródło
1
Chociaż ten kod może odpowiedzieć na pytanie, zapewnienie dodatkowego kontekstu dotyczącego tego, jak i / lub dlaczego rozwiązuje problem, poprawiłoby długoterminową wartość odpowiedzi. Pamiętaj, że odpowiadasz na pytanie czytelników w przyszłości, a nie tylko osoby, która zadaje teraz pytanie! Proszę edytować swoje odpowiedzi, aby dodać wyjaśnienie, i dać wskazówkę co zastosować ograniczenia i założenia. Nie zaszkodzi też wspomnieć, dlaczego ta odpowiedź jest bardziej odpowiednia niż inne.
Dev-iL
-8

Istnieje stała statyczna reprezentująca 0 :

BigDecimal.ZERO.equals(selectPrice)

Powinieneś to zrobić zamiast:

selectPrice.equals(BigDecimal.ZERO)

w celu uniknięcia przypadku, w którym selectPricejest null.

tskuzzy
źródło
3
Zachowanie Java BigDecimal equalsi compareTonie jest takie, jak myślisz. docs.oracle.com/javase/1.5.0/docs/api/java/math/…
nhahtdh
więc dla drugiej linii ... jeśli wybrana cena jest pusta, to po prostu wyrzuci wyjątek NullPointerException.
user3206236