if/else、switch
May 21, 2022現實生活中待解決的事千奇百怪,想使用電腦解決的需求也是各式各樣:「如果」發生了…,就要…;「對於」…,就一直執行…;「如果」…,就「中斷」…。為了告訴電腦特定條件該執行的動作,可使用條件式來定義程式執行流程。
if/else
Java 提供了 if/else
條件式,語法如下:
if(條件式) {
陳述句;
}
else {
陳述句;
}
條件式運算結果為 true
會執行 if
的 {
與 }
的陳述句,否則執行 else
的 {
與 }
的陳述句,如果條件式不成立時並不想作任何事,else
可以省略。
底下來個運用 if/else
判斷數字為奇數或偶數的範例:
package cc.openhome;
public class Odd {
public static void main(String[] args) {
var input = 10;
var remain = input % 2;
if(remain == 1) { // 餘數為1時是奇數
System.out.printf("%d 是奇數%n", input);
}
else {
System.out.printf("%d 是偶數%n", input);
}
}
}
如果 if
或 else
中只有一行陳述句,{
與 }
可以省略,不過為了可讀性與可維護性而言,現在建議是就算只有一行陳述句,也要撰寫 {
與 }
明確定義範圍。
Apple曾經提交一個 iOS 的安全更新,原因是在某個函式中有兩個連續的縮排:
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
goto fail;
因為縮排在同一層,閱讀程式碼時大概也就沒注意到,又沒有 {
與 }
定義區塊,結果就是 goto fail
無論如何都會被執行到的錯誤。
某些人會撰寫所謂的 if/else if
語法:
if(條件式一) {
...
}
else if(條件式二) {
...
}
else {
...
}
其實這是省略 {
與 }
加上程式碼排版後的結果,如果不省略 {
與 }
,原本的程式應該是:
if(條件式一) {
...
}
else {
if(條件式二) {
...
}
else {
...
}
}
如果條件式一不滿足,就執行 else
的陳述,而在這邊進行條件式二測試,如果滿足就執行條件式二 {
與 }
的陳述,如果省略了第一個 else
的 {
與 }
:
if(條件式一) {
...
}
else
if(條件式二) {
...
}
else {
...
}
Java 是個自由格式語言,可以適當地排列這個片段,就會變為方才看到的 if/else if
寫法,就閱讀上似乎比較好讀一些,例如應用在處理學生的成績等級問題:
package cc.openhome;
public class Level {
public static void main(String[] args) {
var score = 88;
var level = '\0';
if(score >= 90) {
level = 'A';
}
else if(score >= 80 && score < 90) {
level = 'B';
}
else if(score >= 70 && score < 80) {
level = 'C';
}
else if(score >= 60 && score < 70) {
level = 'D';
}
else {
level = 'E';
}
System.out.printf("得分等級:%c%n", level);
}
}
switch
switch
可用於比對整數、字元、Enum
、字串,Enum
之後文件會說明。switch
的語法架構如下:
switch(變數或運算式) {
case 整數、字元、字串或Enum:
陳述句;
break;
case 整數、字元、字串或Enum:
陳述句;
break;
...
default:
陳述句;
}
首先看看 switch
的括號,當中置放要取得值的變數或運算式,值必須是整數、字元、字串或 Enum
,取得值後會開始與 case
設定的整數、字元、字串或 Enum
比對,如果符合就執行之後的陳述句,直到遇到 break
離開 switch
區塊,如果沒有符合的整數、字元、字串或 Enum
,會執行 default
的陳述句,default
不一定需要,如果沒有預設要處理的動作,可以省略 default
。
來看看方才的 Level
類別,特意改用 switch
實作會如何:
package cc.openhome;
public class Level2 {
public static void main(String[] args) {
var score = 88;
var quotient = score / 10;
var level = '\0';
switch(quotient) {
case 10:
case 9:
level = 'A';
break;
case 8:
level = 'B';
break;
case 7:
level = 'C';
break;
case 6:
level = 'D';
break;
default:
level = 'E';
}
System.out.printf("得分等級:%c%n", level);
}
}
在這個程式中,使用除法並取得運算後的商數,如果大於 90 的話,除以 10 的商數一定是 9 或 10(100分時),在 case 10
中沒有任何的陳述,也沒有使用 break
,繼續往下執行,直到遇到 break
離開 switch
,如果比對條件不在 10 到 6 這些值的話,會執行 default
的陳述,這表示商數小於 6,所以學生成績等級就顯示為 E 了。
從 Java SE 14 開始,switch
正式支援運算式形式,就上例來說,可以改為以下的形式:
package cc.openhome;
public class Level3 {
public static void main(String[] args) {
var score = 88;
var quotient = score / 10;
var level = switch(quotient) {
case 10, 9 -> 'A';
case 8 -> 'B';
case 7 -> 'C';
case 6 -> 'D';
default -> 'E';
};
System.out.printf("得分等級:%c%n", level);
}
}
在 case
的比對上,可以使用逗號區隔來比對多個案例,每個案例的 ->
右方指定值,會成為 switch
的運算值,如此一來,就不用特別如 Level2
的範例,得為 level
設定初始值了。
在需要區塊的情況下,也可以改用 yield
指定 switch
的運算值,例如:
package cc.openhome;
public class Level4 {
public static void main(String[] args) {
var score = 88;
var quotient = score / 10;
var level = switch(quotient) {
case 10, 9:
yield 'A';
case 8:
yield 'B';
case 7:
yield 'C';
case 6:
yield 'D';
default:
yield 'E';
};
System.out.printf("得分等級:%c%n", level);
}
}
可以看到 switch
作為運算式時,雖然沒有 break
,然而執行完案例後,並不會往下個案例繼續執行;必要時,->
與 yield
可以混合使用:
package cc.openhome;
public class Level5 {
public static void main(String[] args) {
final String warning = "(喔喔!不及格了!)";
var score = 59;
var quotient = score / 10;
var level = switch(quotient) {
case 10, 9 -> "A";
case 8 -> "B";
case 7 -> "C";
case 6 -> "D";
default -> {
String message = "E" + warning;
yield message ;
}
};
System.out.printf("得分等級:%s%n", level);
}
}
就初學者而言,若要將特定值對應至某些動作或值,switch
是個簡單、便利的工具,然而切記不要濫用,若各個 case
的邏輯或層次變得複雜而難以閱讀時,就應考慮其他設計方式的可行性。