10

BigDecimal's equals() method compares scale too, so

new BigDecimal("0.2").equals(new BigDecimal("0.20")) // false

It's contested why it behaves like that.

Now, suppose I have a Set<BigDecimal>, how do I check if 0.2 is in that Set, scale independent?

Set<BigDecimal> set = new HashSet<>();
set.add(new BigDecimal("0.20"));
...
if (set.contains(new BigDecimal("0.2")) { // Returns false, but should return true
    ...
}
Community
  • 1
  • 1
Geoffrey De Smet
  • 26,223
  • 11
  • 73
  • 120

3 Answers3

17

contains() will work as you want it to if you switch your HashSet to a TreeSet.

It is different from most sets as it will decide equality based on the compareTo() method as opposed to equals() and hashCode():

a TreeSet instance performs all element comparisons using its compareTo (or compare) method

And since BigDecimal.compareTo() compares without regard to scale, that's exactly what you want here.

Alternatively you could ensure that all elements in the Set are of the same, minimal scale, by always using stripTrailingZeros (both on add() and on contains()):

set.add(new BigDecimal("0.20").stripTrailingZeros());
...
if (set.contains(new BigDecimal("0.2").stripTrailingZeros()) {
  ...
}
Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
  • Normalizing a `BigDecimal` is apt to be expensive. It would likely be better to have an attempt to storing 123.400 search for 123.400 and--if not found--123.4. If neither was found, create a new wrapper object and store it under both keys. If only the latter was found, store under the former key a reference to the wrapper found under the latter. Normalization is very expensive, so storing the same value multiple ways would be cheaper than having to normalize before every search. – supercat Jul 25 '14 at 23:35
0

HashSet#contains method can't serve your requirement, it implicitly call equals method. You should iterate over Set and use compareTo method. If value is found than set a flag.

    Set<BigDecimal> set = new HashSet<>();
    set.add(new BigDecimal("0.20"));
    boolean found=false;
    for (BigDecimal bigDecimal : set) {
        if(bigDecimal.compareTo(new BigDecimal("0.2"))==0){
            System.out.println("Value is contain");
            found=true;
            break;
        }
    }
    if(found)// Use this flag for codition.
Masudul
  • 21,823
  • 5
  • 43
  • 58
-1

Use the compareTo method of BigDecimal.

BigDecimal("0.200").compareTo(new BigDecimal("0.2")) == 0; // Means they are equal.

From the JavaDoc

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.

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
MystyxMac
  • 1,532
  • 2
  • 14
  • 28
  • Would this work with a set however? Who's .contains method automatically calls .equals () – Richard Tingle Nov 20 '13 at 09:25
  • 1
    Not with a hashset, like the other answer stated. The answer from Joachim Sauer seems to do the trick. But a TreeSet sees 0.200 and 0.2 as the same value (because it uses comparTo instead of equals). But I do think, that's what you want. – MystyxMac Nov 20 '13 at 09:42