1. 前言
我們先從生活化的比喻開始。想像一個食譜:
將麵粉、雞蛋和糖混合,打發,加入奶油,再打發一次。
看起來有點奇怪嗎?現在再想像一下,若在「打發」與「加入」之間加上逗號或括號,步驟的先後立刻就更清楚了。
在程式設計中,當你寫出複雜的運算式時,也會遇到相同情況:
boolean result = a > 0 && b < 10 || c == 3;
先後順序是什麼?先計算: a > 0 && b < 10, 然後 || c == 3? 還是相反呢?
若沒有明確的計算順序,電腦可能會「把食材搞混」,而你的結果就會出乎意料。
2. Java 中的運算子優先順序
Java(與大多數程式語言相同)使用一張既定的運算子優先順序表。
優先順序較高的運算子會先於優先順序較低的運算子被運算。
來看這張表中最重要的部分 (針對條件運算式):
| 運算子 | 說明 | 優先順序 |
|---|---|---|
|
括號 | 最高 |
|
邏輯「非」 | 高 |
|
相等 / 不相等 | 中 |
|
比較 | 中 |
|
邏輯「且」 | 較低 |
|
邏輯「或」 | 更低 |
(另外還有算術運算子 — 它們的優先順序高於邏輯運算子。)
關鍵規則
「且」運算子 (&&) 的優先順序高於「或」 (||),
也就是會先計算「且」,再計算「或」。這並非巧合:「且」相當於邏輯乘法,而「或」相當於邏輯加法。
條件優先順序的流程圖
graph LR
A["a > 0"] --&&--> B["b < 10"]
B --||--> C["c == 3"]
(在實務上: a > 0 && b < 10 || c == 3 — 會先計算 a > 0 && b < 10,然後再經由 || 與 c == 3 合併。)
3. 運算子的結合方向:由左至右與由右至左
除了優先順序之外,還有一個名詞: 結合性.
當多個具有相同優先順序的運算子「相鄰」時,這個規則決定了計算的方向。
範例:
boolean a = true, b = false, c = true;
boolean result = a && b && c;
問題:會怎麼計算?
答案:&& 的結合性是 由左至右.
也就是先 a && b,再把結果與 c 結合。
應用到條件運算式上:
| 運算子 | 結合方向 |
|---|---|
|
由左至右 |
|
由右至左 |
4. 在複雜條件中,括號是你最好的朋友
神奇(而且救命)的地方在這裡。當你撰寫運算式時,括號會改變優先順序,也讓你的程式碼更清楚、更安全。
範例 1(無括號):
// 我們的意圖:「如果使用者是成年人且是公民,或他擁有特殊通行證」
boolean isAdult = age >= 18;
boolean isCitizen = country.equals("白俄羅斯");
boolean hasPermit = hasSpecialPass == true;
if (isAdult && isCitizen || hasPermit)
{
System.out.println("允許進入!");
}
Java 的實際計算方式:
先計算 isAdult && isCitizen,再用 || 與 hasPermit 合併結果。
- 假設,isAdult = true, isCitizen = false, hasPermit = true
- isAdult && isCitizen → true && false → false
- false || true → true
也就是說,只要有特殊通行證,就會被放行。
沒有通行證,但若是成年的公民 — 也會被放行。
範例 2(有括號):
if (isAdult && (isCitizen || hasPermit))
{
System.out.println("允許進入!");
}
現在程式會先檢查:isCitizen || hasPermit,然後再把這個結果與 isAdult 一起判斷。
也就是說,你必須是成年人且(是公民或擁有特殊通行證)。
括號上的小改動 — 邏輯上的大不同!
GO TO FULL VERSION