Java 中 BigDecimal 的 equals() 與 compareTo() 的區別

        這兩天在設計金額表字段類型的時候,在 double 和 decimal 之間猶豫了半天,講道理應該是用decimal的,但是以前的人的表設計是用double的,最終我還是堅持真理用了decimal,雖然都是浮點數,但是用 int(單位:分)再轉換爲 double 來顯示都比直接用 double 靠譜,double 可能會發生一些精度不準的現象,而 decimal 是對象,用方法操作,不直接用運算符運算,在金額方面是很安全的。

【jre7】:equals():

        可以看到BigDecimal的euquals方法是先判斷要比較的數據類型,如果對象類型一致前提下同時判斷精確度(scale)和值(BigInteger的equals方法)是否一致。

/**
 * Compares this {@code BigDecimal} with the specified
 * {@code Object} for equality.  Unlike {@link
 * #compareTo(BigDecimal) compareTo}, this method considers two
 * {@code 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).
 *
 * @param  x {@code Object} to which this {@code BigDecimal} is
 *         to be compared.
 * @return {@code true} if and only if the specified {@code Object} is a
 *         {@code BigDecimal} whose value and scale are equal to this
 *         {@code BigDecimal}'s.
 * @see    #compareTo(java.math.BigDecimal)
 * @see    #hashCode
 */
@Override
public boolean equals(Object x) {
    if (!(x instanceof BigDecimal))
        return false;
    BigDecimal xDec = (BigDecimal) x;
    if (x == this)
        return true;
    if (scale != xDec.scale)
        return false;
    long s = this.intCompact;
    long xs = xDec.intCompact;
    if (s != INFLATED) {
        if (xs == INFLATED)
            xs = compactValFor(xDec.intVal);
        return xs == s;
    } else if (xs != INFLATED)
        return xs == compactValFor(this.intVal);

    return this.inflate().equals(xDec.inflate());
}

 

【jre7】:compareTo()

        可以看到這個方法裏面有個matchScale的處理,意思是把精確度低的那個對象轉換爲高精確度,然後再進行比較(同樣是BigInteger的compareTo方法)。

/**
 * Compares this {@code BigDecimal} with the specified
 * {@code BigDecimal}.  Two {@code 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 ({@literal <}, ==,
 * {@literal >}, {@literal >=}, !=, {@literal <=}).  The
 * suggested idiom for performing these comparisons is:
 * {@code (x.compareTo(y)} &lt;<i>op</i>&gt; {@code 0)}, where
 * &lt;<i>op</i>&gt; is one of the six comparison operators.
 *
 * @param  val {@code BigDecimal} to which this {@code BigDecimal} is
 *         to be compared.
 * @return -1, 0, or 1 as this {@code BigDecimal} is numerically
 *          less than, equal to, or greater than {@code val}.
 */
public int compareTo(BigDecimal val) {
    // Quick path for equal scale and non-inflated case.
    if (scale == val.scale) {
        long xs = intCompact;
        long ys = val.intCompact;
        if (xs != INFLATED && ys != INFLATED)
            return xs != ys ? ((xs > ys) ? 1 : -1) : 0;
    }
    int xsign = this.signum();
    int ysign = val.signum();
    if (xsign != ysign)
        return (xsign > ysign) ? 1 : -1;
    if (xsign == 0)
        return 0;
    int cmp = compareMagnitude(val);
    return (xsign > 0) ? cmp : -cmp;
}

        matchScale():

/**
 * Match the scales of two {@code BigDecimal}s to align their
 * least significant digits.
 *
 * <p>If the scales of val[0] and val[1] differ, rescale
 * (non-destructively) the lower-scaled {@code BigDecimal} so
 * they match.  That is, the lower-scaled reference will be
 * replaced by a reference to a new object with the same scale as
 * the other {@code BigDecimal}.
 *
 * @param  val array of two elements referring to the two
 *         {@code BigDecimal}s to be aligned.
 */
private static void matchScale(BigDecimal[] val) {
    if (val[0].scale == val[1].scale) {
        return;
    } else if (val[0].scale < val[1].scale) {
        val[0] = val[0].setScale(val[1].scale, ROUND_UNNECESSARY);
    } else if (val[1].scale < val[0].scale) {
        val[1] = val[1].setScale(val[0].scale, ROUND_UNNECESSARY);
    }
}

 

做個簡單測試:

System.out.println(new BigDecimal("1.2").equals(new BigDecimal("1.20")));  //輸出false
System.out.println(new BigDecimal("1.2").compareTo(new BigDecimal("1.20")) == 0); //輸出true

 

結論:

        對於BigDecimal的大小比較,用equals方法的話會不僅會比較值的大小,還會比較兩個對象的精確度,而compareTo方法則不會比較精確度,只比較數值的大小

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章