天天看點

電商金額計算的 4 個坑,千萬注意了!

設定标簽前言

電商項目開發時肯定少不了金額計算,金額計算時有很多讓人坑人的地方,在此記錄,以免被坑。

public static void main (String[] args) {
  double num1 = 1;
  double num2 = 31.2;
  double num3 = 323.03;
  System.out.println (num1+num2+num3);
  /**
   * 355.22999999999996
   */
}      

如上代碼,3 個數值想加之後卻得出了一個很長的數值。

在 java 開發中可以通過 BigDecimal 進行數值類型的計算,詳細可到 BigDecimal 工具類。

資料庫也是一樣,mysql中有float和double類型,通過sql直接累加資料也會有精度缺失的情況。如果要精确的數值計算,要使用mysql的decimal類型。

2、包裝類型比對

public static void main(String[] args) {
     Integer i1 = 100;
     Integer i2 = 100;
     Integer i3 = 200;
     Integer i4 = 200;
     System.out.println(i1==i2); // true
     System.out.println(i3==i4);  // false
}      

如上代碼很神奇,同樣是數值比對100的時候可以通過雙等号傳回true。200就傳回false。

這是因為Integer的valueOf()方法。

//Integer的valueOf方法
public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
        return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}      

在[-128,128]之間的數,可以通過雙等于比對成功,之外的數值就會傳回一個new一個新的Integer,是以會傳回false。

Double的比較就簡單一點,雙等于比對全是false。這是因為Double直接是傳回了一個新的Double。      
//Double的valueOf方法
public static Double valueOf(String s) throws NumberFormatException {
    return new Double(parseDouble(s));
}      

在數值比對的時候亂的樣子,那我發現他們都有eq方法,通過這個方法比對可以嗎?

可以的,不管是Integer還是Double都存在一個equas方法,通過這個方法即可進行數值比對。但是這個方法不是很完美。

public static void main (String[] args){
  Double i1 = 100d;
  System.out.println(i1.equals ("100")); 
  //false
}      

如上所示,因為太多的人都知道字元串類型不能用雙等号進行比對,要用eq方法進行比對其value。這樣會讓很多人誤以為Integer和Double類型也是如此,而且在編碼的時候如上這種寫法也沒有報錯,會認為都是100肯定會傳回true。恰巧這種想法是錯誤的。

public boolean equals(Object obj) {
    return (obj instanceof Double)
           && (doubleToLongBits(((Double)obj).value) ==
                  doubleToLongBits(value));
}      

Double的eq方法入參是Object類型,是以不管傳入什麼類型都不會報錯。i1.equals ("100")這種就是雙精度和字元進行比對,這兩個永遠都不可能傳回true。正确的寫法應該是i1.equals (100d)。

但是盡管多次提醒,但是還是會有不認真的開發小夥伴錯誤,是以,可以使用Double.compareTo方法,這個方法和eq方法類似,但是有編譯的異常,這樣可有效的提醒開發人員。

public static void main (String[] args){
  Double i1 = 100d;
  System.out.println(i1.compareTo (100d)); //0
  System.out.println(i1.compareTo (1d));  //1
}      

3、除以0會怎樣?

國小的時候就講過,進行除法運算時,除以0是沒有意義的,開發過程中也是如此, 發現可能存在除以0的場景要特别注意,程式不會抛出異常,竟然會傳回一個字元串!雖然這種場景不多,但是還是需要了解一下。

1除以0的場景:

public static void main(String[] args) {
  Double d = 1d;
  double v = d / 0d;
  System.out.println(v);
  //Infinity
}      

0除以0的場景:

public static void main(String[] args) {
  Double d = 0d;
  double v = d / 0d;
  System.out.println(v);
  //NaN
}      

4、float轉double

public static void main(String[] args) {
    Float f = 12312.12f;
    System.out.println(f.doubleValue()); 
    System.out.println(Double.parseDouble (f.toString ())); 
    //12312.1201171875
    //12312.12
}      

Float類中有一個doubleValue方法,傳回值是一個double類型,這樣會很容易的以為這是float轉換double類型。但是轉換之後精度缺失了,隻能乖乖的換一種方式轉換。