程式目的簡單地說就是運算,除了運算還是運算,程式語言中提供運算功能的就是運算子(Operator)。
算術運算
與算術相關的運算子+、-、*、/
,也就是加、減、乘、除這類運算子,另外%
,稱為模數運算子或餘除運算子。算術運算子使用上與你學過的加減乘除一樣,也是先乘除後加減。例如以下程式碼片段會在文字模式下顯示7:
System.out.println(1 + 2 * 3);
以下程式碼會顯示的是6:
System.out.println(2 + 2 + 8 / 4);
如果你想要的是2 + 2 + 8加總後,再除以4,請加上括號表示運算先後順序。例如以下程式碼顯示的是3:
System.out.println((2 + 2 + 8) / 4);
%
運算子計算的結果是除法後的餘數,例如10 % 3
會得到餘數1;一個使用%的例子是數字循環,假設有個立方體要進行360度旋轉,每次要在角度上加1,而360度後必須復歸為0重新計數,這時可以這麼撰寫:
int count = 0;
....
count = (count + 1) % 360;
在運算子的兩邊各留一個空白,這樣比較容易閱讀。
比較、條件運算
數學上有大於、等於、小於的比較運算,Java中也提供了這些運算子,這些運算子稱之為比較運算子(Comparison operator),它們有大於(>
)、不小於(>=
)、小於(<
)、不大於(<=
)、等於(==
)以及不等於(!=
),比較條件成立時以boolean
型態true
表示,比較條件不成立時以false
表示。以下程式片段示範了幾個比較運算的使用:
package cc.openhome;
public class Comparison {
public static void main(String[] args) {
System.out.printf("10 > 5 結果 %b%n", 10 > 5);
System.out.printf("10 >= 5 結果 %b%n", 10 >= 5);
System.out.printf("10 < 5 結果 %b%n", 10 < 5);
System.out.printf("10 <= 5 結果 %b%n", 10 <= 5);
System.out.printf("10 == 5 結果 %b%n", 10 == 5);
System.out.printf("10 != 5 結果 %b%n", 10 != 5);
}
}
程式的執行如下所示:
10 >= 5 結果 true
10 < 5 結果 false
10 <= 5 結果 false
10 == 5 結果 false
10 != 5 結果 true
==
是兩個連續的=組成,而不是一個=
,一個=
是指定運算,這點必須特別注意。例如若變數x
與y
要比較是否相等,應該是寫成x == y
,而不是寫成x = y
,後者作用是將y
的值指定給x
,而不是比較運算x
與y
是否相等。對於類別型態宣告的參考名稱來說,兩個參考名稱使用==
比較時,是比較兩個名稱是否參考至同一物件,之後介紹物件會再詳細介紹。Java有個條件運算子(Conditional operator),使用方式如下:
條件式 ? 成立傳回值 : 失敗傳回值
條件運算子傳回值依條件式結果而定,如果條件式結果為
true
,則傳回:前的值,若為false
,則傳回:後的值。例如,若score
是int
宣告,儲存了使用者輸入的學生成績,以下程式片段可用來判斷學生是否及格:System.out.printf("該生是否及格?%c%n", score >= 60 ? '是' : '否');
條件運算子使用適當的話可以少寫幾句程式碼。例如,若
number
是int
宣告,儲存使用者輸入的數字,則以下程式片段可判斷奇數或偶數:System.out.printf("是否為偶數?%c%n", (number % 2 == 0) ? '是' : '否');
同樣的程式片段,若改用本章稍後要介紹的
if..else
語法,則要如下撰寫:if(number % 2 == 0) {
System.out.println("是否為偶數?是");
}
else {
System.out.println("是否為偶數?否");
}
邏輯運算
&&
(AND)、||
(OR)及!
(NOT)。看看以下的程式片段會輸出什麼結果?int number = 75;
System.out.println(number > 70 && number < 80);
System.out.println(number > 80 || number < 75);
System.out.println(!(number > 80 || number < 75));
三段陳述句分別會輸出
true
、false
與true
三種結果,分別表示number
大於70且小於80為真、number
大於80或小於75為假、number
大於80或小於75的相反為真。&&
與||
有所謂捷徑運算(Short-Circuit Evaluation)。因為AND只要其中一個為假,就可以判定結果為假,所以對&&
來說,只要左運算元(Operand)評估為false
,就會直接傳回false
,不會再去運算右運算元。因為OR只要其中一個為真,就可以判定結果為真,所以對||
來說,只要左運算元評估為true
,就會直接傳回true
,就不會再去運算右運算元。來舉個運用捷徑運算的例子,在Java中兩個整數相除,若除數為0會發生
ArithmeticException
,代表除0的錯誤,以下運用&&
捷徑運算避免了這個問題:if(b != 0 && a / b > 5) {
// 作一些事...
}
在這個程式片段中,變數
a
與b
都是int
型態,如果b
為0的話,&&
左邊運算元結果就是false
,直接判斷整個&&
的結果應是false
,不用再去評估右運算元,從而避免了a /b
而b
等於0時的除零錯誤。位元運算
&
(AND)、|
(OR)、^
(XOR)與~(補數)。如果不會基本位元運算,可以從以下範例瞭解各個位元運算結果: package cc.openhome;
public class Bitwise {
public static void main(String[] args) {
System.out.println("AND運算:");
System.out.printf("0 AND 0 %5d%n", 0 & 0);
System.out.printf("0 AND 1 %5d%n", 0 & 1);
System.out.printf("1 AND 0 %5d%n", 1 & 0);
System.out.printf("1 AND 1 %5d%n", 1 & 1);
System.out.println("\nOR運算:");
System.out.printf("0 OR 0 %6d%n", 0 | 0);
System.out.printf("0 OR 1 %6d%n", 0 | 1);
System.out.printf("1 OR 0 %6d%n", 1 | 0);
System.out.printf("1 OR 1 %6d%n", 1 | 1);
System.out.println("\nXOR運算:");
System.out.printf("0 XOR 0 %5d%n", 0 ^ 0);
System.out.printf("0 XOR 1 %5d%n", 0 ^ 1);
System.out.printf("1 XOR 0 %5d%n", 1 ^ 0);
System.out.printf("1 XOR 1 %5d%n", 1 ^ 1);
}
}
執行結果就是各個位元運算的結果:
0 AND 0 0
0 AND 1 0
1 AND 0 0
1 AND 1 1
OR運算:
0 OR 0 0
0 OR 1 1
1 OR 0 1
1 OR 1 1
XOR運算:
0 XOR 0 0
0 XOR 1 1
1 XOR 0 1
1 XOR 1 0
位元運算是逐位元運算,例如10010001與01000001作AND運算,是一個一個位元對應運算,答案就是00000001。補數運算是將所有位元0變1,1變0。例如00000001經補數運算就會變為11111110。例如:
byte number = 0;
System.out.println(~number);
上面的程式片段會顯示-1,因為
byte
佔記憶體一個位元組,number
儲存的0在記憶體中是的位元00000000,經補數運算就變成11111111,這個數在電腦中用整數表示則是-1。 邏輯運算子與位元運算子也是很常被混淆的,像是
&&
與&
,||
與|
,初學時可得多注意。在位元運算上,Java還有左移(
<<
)與右移(>>
)兩個運算子,左移運算子會將所有位元往左移指定位數,左邊被擠出去的位元會被丟棄,而右邊補上0;右移運算則是相反,會將所有位元往右移指定位數,右邊被擠出去的位元會被丟棄,至於最左邊補上原來的位元,如果左邊原來是0就補0,1就補1。還有個>>>
運算子,這個運算子在右移後,最左邊一定是補0。使用左移運算來作簡單的2次方運算示範:
package cc.openhome;
public class Shift {
public static void main(String[] args) {
int number = 1;
System.out.printf( "2 的 0 次方: %d%n", number);
System.out.printf( "2 的 1 次方: %d%n", number << 1);
System.out.printf( "2 的 2 次方: %d%n", number << 2);
System.out.printf( "2 的 3 次方: %d%n", number << 3);
}
}
2 的 1 次方: 2
2 的 2 次方: 4
2 的 3 次方: 8
實際來左移看看就知道為何可以如此作次方運算了:
00000001 -> 1
00000010 -> 2
00000100 -> 4
00001000 -> 8
位元運算你可能不常用,通常應用於影像處理、文字編碼等場合,例如 亂碼 1/2 就有一些位元運算的例子。
遞增、遞減運算
在程式中對變數遞增1或遞減1是很常見的運算,例如:
int i = 0;
i = i + 1;
System.out.println(i);
i = i - 1;
System.out.println(i);
這個程式片段會分別顯示出1與0兩個數,你可以使用遞增、遞減運算子來撰寫程式:
int i = 0;
i++;
System.out.println(i);
i--;
System.out.println(i);
那麼哪個寫法比較好呢?就簡潔度而言,使用++
、--
的寫法比較好,就效率而言,其實沒差,因為如果你寫i = i + 1
,編譯器會自動幫你改成i++
,同樣地,如果你寫i = i – 1
,編譯器會自動幫你改為i--
。
上面的程式片段還可以再簡潔一些:
int i = 0;
System.out.println(++i);
System.out.println(--i);
可以將++
或--
運算子撰寫在變數的前或後,不過兩種寫法有差別,將++
或--
運算子寫在變數前,表示先將變數值加或減1,然後再傳回變數值,將++
或--
運算子寫在變數後,表示先傳回變數值,然後再對變數加或減1。例如:
int i = 0;
int number = 0;
number = ++i; // 結果相當於i = i + 1; number = i;
System.out.println(number);
number = --i; // 結果相當於i = i - 1; number = i;
System.out.println(number);
在這個程式片段中,number
的值會前後分別顯示為1與0。再來看個例子:
int i = 0;
int number = 0;
number = i++; // 相當於number = i; i = i + 1;
System.out.println(number);
number = i--; // 相當於 number = i; i = i - 1;
System.out.println(number);
在這個程式片段中,number
的值會前後分別顯示為0與1。
指定運算
到目前為止只看過一個指定運算子,也就是=這個運算子,事實上指定運算子還有以下幾個:
指定運算子 |
範例 |
結果 |
+= |
a += b |
a = a + b |
-= |
a -= b |
a = a - b |
*= |
a *= b |
a = a * b |
/= |
a /= b |
a = a / b |
%= |
a %= b |
a = a % b |
&= |
a &= b |
a = a & b |
|= |
a |= b |
a = a | b |
^= |
a ^= b |
a = a ^ b |
<<= |
a <<= b |
a = a << b |
>>= |
a >>= b |
a = a >> b |