Serguey Asael Shinder: BigDecimal.equals says 2.0 and 2.00 are different, and it means it
This returns false:
new BigDecimal("1.0").equals(new BigDecimal("1.00"))
and it is not a bug. The javadoc for BigDecimal.equals is explicit:
"Unlike
compareTo, this method considers two BigDecimal objects equal only if they are equal in value and scale. Therefore 2.0 is not equal to 2.00 when compared by this method since the former has[BigInteger, scale]components equal to[20, 1]while the latter has components equal to[200, 2]."
compareTo does the other thing, and its javadoc says so:
"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."

So BigDecimal has two different notions of "the same number", and equals is the one that does not mean what a numeric type usually means by equality. The place this bites is any collection or comparison that goes through equals and hashCode:
Set<BigDecimal> prices = new HashSet<>();
prices.add(new BigDecimal("1.0"));
prices.contains(new BigDecimal("1.00")); // false
prices.add(new BigDecimal("1.00")); // now the set has two "1"s
A HashSet, a HashMap key, List.contains, distinct() in a stream — all of them use equals, so all of them treat 1.0 and 1.00 as distinct. Money code is where this is worst, because scale is exactly what money code carries around: the same amount arriving from two sources with different trailing zeros silently becomes two amounts.
The fixes, in order of preference:
Compare with compareTo when you mean numeric equality. The idiom is a.compareTo(b) == 0. It is more typing than equals and it is the correct thing, and it is what the javadoc itself recommends over the individual comparison operators.
Normalise the scale before the value goes into a collection. If everything is stored at a fixed scale — setScale(2, RoundingMode.HALF_EVEN) for currency — then equals and compareTo agree again, because the scale is no longer varying. This is usually the right answer for money: pick the scale once, at the boundary, and hold it.
Do not reach for stripTrailingZeros as the fix. It removes trailing zeros, which makes 1.0 and 1.00 compare equal under equals — but it can also turn 600 into 6E+2, and now you have a different surprising scale. It solves the example and creates a new one.
Reference: https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/math/BigDecimal.html