所謂的資料型態就是儲存資料的種類,比如Excel中可以針對文字、數字、日期不同種類的資料進行儲存跟運算,程式語言中也是如此,目的都是幫你把各種資料放到電腦記憶中進行加減乘除的運算,Java Primitive Type,我們稱為基本型態,一共有8種分別是整數有4種(byte short int long)、小數2種(float double)、文字以及布林值。
這裏我們提兩件重要的事
Overflow 資料溢位
Overflow中文翻譯成叫「資料溢位」,這名詞翻的很道地,就明白的跟你說資料多到滿出來了。
int overflow = 2000000000 + 2000000000; <- 這裏是20億(2後面9個0)加上20億,正常應該是40億
System.out.println("overflow = " + overflow);
執行結果如下:
overflow = -294967296
結果是一個負值,這其實是因為加起來後其實是40億,但已經超過了int 21億的範圍,導致加相後的位元溢出至正負號位而發生的錯誤。這種錯誤很危險,因為在執行過程中並沒有任何錯誤訊息提示。
想像一下如果你有20億,你再存了20億去銀行,但櫃台跟你說:先生,你現在欠我們銀行2億多。
int的極限值可以利用以下程式,最大值大概是21億多
System.out.println(Integer.MAX_VALUE);//最大值:2147483647
System.out.println(Integer.MIN_VALUE);//最小值:-2147483648
那宣告成long應該就沒問題了吧
long overflow = 2000000000 + 2000000000;
計算的結果依然是 -294967296
結果依然是負值,原因是Java運算中有一個規則
若符號(+)兩邊以相同型態的變數運算時(以這個例子來說就是上方的2個20億都是int,也就是 int+ int),則運算結果也會為同一型態(int),也因為最後計算的結果還是int,int又只能放入21億左右的值,放不下40億,所以計算的結果還是會發生overflow。
Java Language Spec 5.6.2 中有明確定義了在兩個不同型態的變數計算時的運算規則。
如果符號左右兩側的變數型態不同呢?有以下的規則
- If either operand is of type
double
, the other is converted todouble
. - Otherwise, if either operand is of type
float
, the other is converted tofloat
. - Otherwise, if either operand is of type
long
, the other is converted tolong
. - Otherwise, both operands are converted to type
int
.
簡單的來說,如果有一邊型態是double,則自動把另一邊轉成double,以下面的例子來說a是double, b 的型態是int,計算時會double + int ,會自動把另一邊轉成double,再進行運算,此時因為兩邊都是double,所以計算結果也會是double。
double a = 3.0;
int b = 10;
double c = a + b ;
// =double + int -> double + double -> 結果為double
以照上述官方的規則,由上往下判斷
- 如果兩邊沒有double,就看看有沒有float,有任何一邊變數為float就都轉成float
- 如果兩邊沒有double float,就看看有沒有long,計算的結果為long
- 兩邊找不到double float long,就都轉成int進行計算,所以計算的結會是int
在這個例子裏,計算時就只能使用long來處理,比如把第一個20億改成long的型態,就是加個L在最後面
long overflow = 2000000000L + 2000000000;
= long + int
把另一邊轉成long= long + long -> long
計算的結果 4000000000就不會因為存到int中而導致overflow
浮點數的精度
浮點數包含了float 跟 double,其中float為單精度浮點數(精度6~7位) 4 bytes,double為雙精度浮點數(15~16位) 8 bytes。我們來看一下什麼是精度
float a= 123.4567890123456789f;
double b=123.4567890123456789;
System.out.println(a);//結果 123.45679
System.out.println(b);//結果 123.45678901234568
System.out.println(0.1+0.1+0.1); //0.30000000000000004
- 精度上,float最多只能記錄7位數字,所以System.out.println(a) 只能印出123.45679。(劃線的部分只有7位)
- double大概15-16位左右,System.out.println(b); 印出 123.45678901234568。(劃線的部分只有16位)
- 在計算上也會造成誤差,0.1+0.1+0.1,最後卻在小數點很後面的地方多了一個4出來
- float 跟double在使用上必須留意,因為有精度上的問題,加減乘除多了會造成精度損失被放大,在計算錢的方面某些情境下可能不適合,需要小數點精細計算可以使用java.math.BigDecimal替代進行較精確的計算。
- 精度雖然有誤差,但計算速度很快,在能接受誤差的情況下就很適合使用。比如我們的需求只是要記錄一公升汽油可以跑幾公里,有些誤差是無傷大雅的。