Java中的BigDecimal類和int和Integer總結

前言

咱們都知道浮點型變量在進行計算的時候會出現丟失精度的問題。以下一段代碼:java

System.out.println(0.05 + 0.01);
System.out.println(1.0 - 0.42);
System.out.println(4.015 * 100);
System.out.println(123.3 / 100);

輸出:
0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999

能夠看到在Java中進行浮點數運算的時候,會出現丟失精度的問題。那麼咱們若是在進行商品價格計算的時候,就會出現問題。頗有可能形成咱們手中有0.06元,卻沒法購買一個0.05元和一個0.01元的商品。由於如上所示,他們兩個的總和爲0.060000000000000005。這無疑是一個很嚴重的問題,尤爲是當電商網站的併發量上去的時候,出現的問題將是巨大的。可能會致使沒法下單,或者對帳出現問題。因此接下來咱們就可使用Java中的BigDecimal類來解決這類問題。api

Java中float的精度爲6-7位有效數字。double的精度爲15-16位緩存

API

方法                    描述                         
  add(BigDecimal)       BigDecimal對象中的值相加,而後返回這個對象。
  subtract(BigDecimal)  BigDecimal對象中的值相減,而後返回這個對象。
  multiply(BigDecimal)  BigDecimal對象中的值相乘,而後返回這個對象。
  divide(BigDecimal)    BigDecimal對象中的值相除,而後返回這個對象。
  toString()            將BigDecimal對象的數值轉換成字符串。    
  doubleValue()         將BigDecimal對象中的值以雙精度數返回。   
  floatValue()          將BigDecimal對象中的值以單精度數返回。   
  longValue()           將BigDecimal對象中的值以長整數返回。    
  intValue()            將BigDecimal對象中的值以整數返回。

BigDecimal精度也丟失

咱們在使用BigDecimal時,使用它的BigDecimal(String)構造器建立對象纔有意義。其餘的如BigDecimal b = new BigDecimal(1)這種,仍是會發生精度丟失的問題。以下代碼:併發

BigDecimal a = new BigDecimal(1.01);
BigDecimal b = new BigDecimal(1.02);
BigDecimal c = new BigDecimal("1.01");
BigDecimal d = new BigDecimal("1.02");
System.out.println(a.add(b));
System.out.println(c.add(d));

輸出:
2.0300000000000000266453525910037569701671600341796875
2.03

可見論丟失精度BigDecimal顯的更爲過度。可是使用Bigdecimal的BigDecimal(String)構造器的變量在進行運算的時候卻沒有出現這種問題。 究其緣由計算機組成原理裏面都有,它們的編碼決定了這樣的結果。long能夠準確存儲19位數字,而double只能準備存儲16位數字。double因爲有exp位,能夠存16位以上的數字,可是須要以低位的不精確做爲代價。若是須要高於19位數字的精確存儲,則必須用BigInteger來保存,固然會犧牲一些性能。因此咱們通常使用BigDecimal來解決商業運算上丟失精度的問題的時候,聲明BigDecimal對象的時候必定要使用它構造參數爲String的類型的構造器。ide

同時這個原則Effective Java和MySQL
必知必會中也都有說起。float和double只能用來作科學計算和工程計算。商業運算中咱們要使用BigDecimal。性能

正確運用BigDecimal

BigDecimal BigDecimal(double d); //不容許使用
BigDecimal BigDecimal(String s); //經常使用,推薦使用
static BigDecimal valueOf(double d); //經常使用,推薦使用
其緣由有網站

  • double 參數的構造方法,不容許使用!!!!由於它不能精確的獲得相應的值;
  • String 構造方法是徹底可預知的: 寫入 new BigDecimal("0.1") 將建立一個 BigDecimal,它正好等於預期的0.1; 所以,一般建議優先使用 String 構造方法;
  • 靜態方法 valueOf(double val) 內部實現,還是將 double 類型轉爲 String 類型; 這一般是將 double(或float)轉化爲 BigDecimal 的首選方法;

BigDecimal 的大小比較

例子:a.compareTo(b) < 0編碼

compareTo 返回: -1,0,1code

-1 小於
0 等於
1 大於
對象

BigDecimal 的小數點後位數

BigDecimal c = new BigDecimal("2.224667").setScale(2, BigDecimal.ROUND_UP);
System.out.println(c);//2.23 跟上面相反,進位處理
----------
ROUND_CEILING 天花板(向上):正數進位向上,負數舍位向上
BigDecimal f = new BigDecimal("2.224667").setScale(2, BigDecimal.ROUND_CEILING);
System.out.println(f);//2.23 若是是正數,至關於BigDecimal.ROUND_UP

BigDecimal g = new BigDecimal("-2.225667").setScale(2, BigDecimal.ROUND_CEILING);
System.out.println(g);//-2.22 若是是負數,至關於BigDecimal.ROUND_DOWN
----------
ROUND_FLOOR 地板(向下):正數舍位向下,負數進位向下
BigDecimal h = new BigDecimal("2.225667").setScale(2, BigDecimal.ROUND_FLOOR);
System.out.println(h);//2.22 若是是正數,至關於BigDecimal.ROUND_DOWN

BigDecimal i = new BigDecimal("-2.224667").setScale(2, BigDecimal.ROUND_FLOOR);
----------
ROUND_HALF_UP
BigDecimal d = new BigDecimal("2.225").setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("ROUND_HALF_UP"+d); //2.23 四捨五入(若捨棄部分>=.5,就進位)
----------
ROUND_HALF_DOWN
BigDecimal e = new BigDecimal("2.225").setScale(2, BigDecimal.ROUND_HALF_DOWN);
System.out.println("ROUND_HALF_DOWN"+e);//2.22 四捨五入(若捨棄部分>.5,就進位)
----------

int和Integer的區別

  • int是java提供的8種原始類型之一,java爲每一個原始類型提供了封裝類,Integer是int的封裝類。int默認值是0,而Integer默認值是null;
  • int和Integer(不管是否new)比較,都爲true, 由於會把Integer自動拆箱爲int再去比;
  • Integer是引用類型,用==比較兩個對象,其實比較的是它們的內存地址,因此不一樣的Integer對象確定是不一樣的;
  • 可是對於Integer i=,java在編譯時會將其解釋成Integer i=Integer.valueOf();。可是,Integer類緩存了[-128,127]之間的整數, 因此對於Integer i1=127;與Integer i2=127; 來講,i1==i2,由於這二個對象指向同一個內存單元。 而Integer i1=128;與Integer i2=128; 來講,i1==i2爲false。

各自的應用場景

  • Integer默認值是null,能夠區分未賦值和值爲0的狀況。好比未參加考試的學生和考試成績爲0的學生
  • 加減乘除和比較運算較多,用int
  • 容器裏推薦用Integer。 對於PO實體類,若是db裏int型字段容許null,則屬性應定義爲Integer。 固然,若是系統限定db裏int字段不容許null值,則也可考慮將屬性定義爲int。
  • 對於應用程序裏定義的枚舉類型, 其值若是是整形,則最好定義爲int,方便與相關的其餘int值或Integer值的比較
  • Integer提供了一系列數據的成員和操做,如Integer.MAX_VALUE,Integer.valueOf(),Integer.compare(),compareTo(),不過通常用的比較少。建議,通常用int類型,這樣一方面省去了拆裝箱,另外一方面也會規避數據比較時可能帶來的bug。
相關文章
相關標籤/搜索