第 5 章 流程控制 (一): 條件分支
本章提要 5-1 甚麼是流程控制? 5-2 if 條件分支 5-3 switch 多條件分支 5-4 綜合演練
5-1 甚麼是流程控制? 在說明流程控制前, 先了解何謂流程?以一天的生活為例, 『早上起床後, 會先刷牙洗臉, 接著吃完早餐後就出門上課, 上完了早上的三堂課, 在餐廳吃自助餐, 午休後繼續上下午的課, 下課後跟同學相約去外面的小吃店用餐, 晚上回宿舍唸書, 最後上床睡覺』, 結束一天的流程。程式的執行也是相同的, 如前所述, 程式在執行時是以敘述為單元,由上往下循序進行。如下圖:
甚麼是流程控制? 由圖不難發現, 程式的執行就如同平常的生活一樣, 是有順序性地在執行, 整個執行的順序與過程, 就是流程。
甚麼是流程控制? 但是流程並非僅僅依序進行, 它可能會因為一些狀況而變化。例如下午老師請假沒來上課, 下午的課就會取消, 因而更改流程, 變成『早上起床後, 先刷牙洗臉, 接著吃完早餐後出門上課, 上完了早上的三堂課, 由於下午老師請假, 因此決定去學校外面吃午餐, 並在市區逛街, 下午再回學校後去打球等』。程式中的流程也是一樣, 可能會因為狀況不同而改變, 執行不同的敘述, 如下圖:
甚麼是流程控制? 因此, 對於程式執行的流程順序以及因應不同狀況而選取不同的流程, 即為流程控制。
甚麼是流程控制? 在 Java 中, 對流程的控制敘述大致可以分為兩大類, 一為條件判斷敘述 (或稱為選擇敘述), 包含有 if 以及 switch 敘述兩種, 會在這一章詳細說明;另一類為迴圈式敘述 (或稱重複敘述), 將留待下一章介紹。
5-2 if 條件分支 在條件判斷敘述中, 最常用到的就是 if 敘述了, 它就如同日常生活中常使用的『如果..就..否則..』是一樣的意思。比方說下述的情況: 以圖形來表示就是:
if 條件分支
if 條件分支 在 Java 程式中判斷當然不是使用這麼口語的說法, 而是使用 if 敘述來依條件判斷的結果執行對應的程式敘述。if 敘述的語法如下:
if 條件分支 if:『如果』 的意思。會根據條件運算式的結果, 來判斷是否執行敘述中的程式。如果條件運算式的結果為 true, 則執行區塊內的敘述;如果結果為 false, 則跳過區塊。 條件運算式:運算結果為布林型別的運算式, 通常由比較運算或邏輯運算所組成。 敘述:條件運算式結果為 true 時所要執行的動作。如果只有單一敘述, 則可以省略大括號。
if 條件分支 以生活中常見的例子來說, 使用 if 判斷汽車是否該加油的程式可以寫成這樣:
if 條件分支
If 條件分支
if 條件分支 第 1、6、11 ~ 18 行是為了讓使用者可以輸入代表目前油量的數值而加上的程式, 這些程式我們會在第 16 章做說明。 第 15 行的 『br.readLine()』 就是讓使用者輸入資料的動作, 執行到這一行時, 會等待使用者輸入資料並按下 [Enter] 鍵之後才會繼續執行, 並且將輸入的資料放入 str 這個字串變數中。
if 條件分支 第 18 行的 『Integer.parseInt(str)』 則是將 str 變數中所儲存以數字組成的字串轉換成 int 型別的數值, 然後放入 liter 變數中。往後在需要使用者輸入資料的範例中, 都會出現第 1~3 所描述的這幾行程式,這裡您只需要知道這幾行的用途即可, 等到後續的章節就會一一說明各行程式的意義。
if 條件分支 第 20 行就是 if 敘述, 它會以 liter 變數的內容為判斷依據, 以決定是否執行第 19 行的敘述。 在執行結果 1 中, 輸入的剩餘汽油量為 2 公升, if 的條件運算式『(liter < 2)』的運算結果為 false, 因此 Java 會忽略第 17 行的敘述, 直接執行第 18 行之後的的程式。
if 條件分支 在執行結果 2 中, 輸入的剩餘汽油量小於 2 公升, 此時 if 的條件運算式結果為 true, 執行第 17 行動作敘述 『System.out.println (“目前油量已經不足, 該去加油了!”);』。 程式流程如下:
if 條件分支
if 條件分支 要提醒的是, 如果符合條件時所要執行的敘述不只一個, 就必須使用一對大括號將這些敘述括起來成為一個區塊, 例如:
if 條件分支
if 條件分支
if 條件分支
if 條件分支 若忘記加上大括號, 而將 if 敘述寫成這樣: 那麼不管輸入甚麼資料, 都會執行第 22 行:
if 條件分支 因為對應於 if 條件的敘述只有第 21 行, 因此第 22 行並不受 if 條件的影響, 一定都會執行。
多條件運算式與巢狀 if 由於 if 是藉由條件運算式的結果來決定是否繼續指定的敘述, 而條件運算式通常是由比較運算子以及邏輯運算子所構成, 像是 CheckOil.java 中的『if (liter < 2)』 就是利用了 『<』 這個比較運算子來判斷。您也可以由多個比較運算子或是邏輯運算子來組成條件運算式:
多條件運算式與巢狀 if
多條件運算式與巢狀 if
多條件運算式與巢狀 if 第 17 行的 『if ((liter >= 2) & (liter < 5))』 就是使用邏輯運算子 & 將兩個條件運算式結合成條件運算式, 只有在 liter 的值大於或等於 2 且小於 5 的時候運算結果才是 true。
多條件運算式與巢狀 if 同樣的程式也可以改寫這樣:
多條件運算式與巢狀 if
多條件運算式與巢狀 if
多條件運算式與巢狀 if 上述例子執行的結果雖與 CheckOil2.java 相同, 不過卻是利用了巢狀 if 敘述。剩餘油量必須先在 17 行第 1 個 if 的條件運算式 (liter >= 2) 成立時, 才會繼續執行第 18 行的 if 敘述, 並在滿足其條件 (liter < 5) 時, 才會執行第19 行的敘述。
多條件運算式與巢狀 if 由流程圖可以看出其差異性:
多條件運算式與巢狀 if
加上 else if 的多條件敘述 除了巢狀 if 的使用方式外, 也可以加上多個 else if 讓程式流程配合較為複雜的規則來執行。語法如右:
加上 else if 的多條件敘述 當條件運算式 1 的結果為 true 時, 就執行 if 區塊內的敘述;否則就檢查條件運算式 2 的結果, 如果是 true, 就執行第 2 個 if 區塊內的敘述;依此類推, 如果前面 if 的條件運算式結果都是 false, 就檢查條件運算式 n 的結果, 如果是true, 就執行第 n 個 if 區塊內的敘述。同樣的, 個別 if 區塊中如果僅有單一敘述, 就可以省略成對的大括號。
加上 else if 的多條件敘述 以上述檢查油量的程式為例, 就可以新增更多的條件來控制程式流程, 例如:
加上 else if 的多條件敘述
加上 else if 的多條件敘述
加上 else if 的多條件敘述
加上 else if 的多條件敘述 這裡每一個 else if 都是額外的條件, 程式執行時, 會從 if 及後續的 else if 中挑選第一個條件運算式結果為 true 的敘述來執行, 以口語來說就是:
加上 else if 的多條件敘述 以流程圖表示如下:
加上 else if 的多條件敘述 因此, 當輸入 1 時, 第 1 個符合的就是條件 1 ;輸入 4 時第 1 個符合的就是條件 2 ;輸入 10 時第 1 個符合的就是條件 3, 執行的就是個別條件對應的敘述。
注意個別條件的順序 在使用多條件的 if 敘述時, 請特別留意個別條件的順序。舉例來說, 如果將 CheckOil3.java 中的條件順序顛倒, 變成這樣:
注意個別條件的順序
注意個別條件的順序 當輸入 1 時, 執行結果就會錯誤:
注意個別條件的順序 這是因為輸入 1 時, 第 21 行的條件就成立了, 根本不會檢查到第 25 行的條件, 所以就會顯示錯誤的結果。請記得在使用多條件的 if 時, 要先列最嚴苛的條件, 條件越寬鬆的越往後移。
捕捉其餘狀況的 else 在使用 if 敘述時, 還可以加上 else 區塊在所有條件都不成立的狀況下, 執行指定的動作。語法如右:
捕捉其餘狀況的 else 當 else 之前的所有 if 的條件運算式結果都是 false 時, 就會執行最後的 else 區塊的敘述。如果 else 區塊內僅有單一敘述, 也同樣可以省略成對的大括號。 以前述的 CheckOil3.java 為例, 就可以改寫為這樣:
捕捉其餘狀況的 else
捕捉其餘狀況的 else
捕捉其餘狀況的 else
捕捉其餘狀況的 else 第 25 行的 else 會在最前面的 if 以及後續的任何 else if 的條件運算式都不成立的情況下成立, 並執行其對應的敘述。因此, 這個程式其實就和CheckOil3.java 是一模一樣的, 因為前 2 個條件都不成立的話,表示 liter 一定大於或是等於 10 。
5-3 switch 多條件分支 除了使用 if 加上多個 else if 來針對不同的條件控制流程外, Java 還提供另一種多條件分支的敘述 ― switch。 switch 是一種多選一的敘述。舉個例子來說, 在本年度初, 我們對自己訂了幾個目標, 如果年度考績拿到優, 就出國去玩;如果拿到甲, 就買台電腦犒賞自己;拿到乙, 就去逛個街放鬆一下;如果考績是丙, 就要準備翻報紙找工作了:
switch 多條件分支 switch 多條件分支的用法與上述的情況十分類似, 是由一個條件運算式的值來決定應執行的對應敘述, 語法如下:
switch 多條件分支
switch 多條件分支 switch:『選擇..』的意思, 表示要根據條件運算式的結果, 選擇接下來要執行哪一個 case 內的動作。switch之後的條件運算式的運算結果必須是 char、byte、short、或是 int 型別的值, 否則編譯時會出現錯誤。
switch 多條件分支 case:列出個別的條件, case 之後的條件值必須是常數或是由常數所構成的運算式, 且不同的 case 的條件值運算結果不能相同。switch 會根據條件運算式的運算結果, 從各個 case 挑選相同的條件值, 並執行對應的敘述。 break:結束 case。
switch 多條件分支 雖然 switch 表面上看起來跟 if 完全不同, 但是 switch 私底下仍然是使用條件運算式與條件值的比較來作為其控制流程的機制。如下圖:
switch 多條件分支
switch 多條件分支 根據上述 switch 語法, 年度考績的例子就可以寫成如右的 switch 程式片段:
switch 多條件分支 以下是實際的程式範例, 我們將設計一個可以依季節來判斷該穿的衣服的程式:
switch 多條件分支
switch 多條件分支
switch 多條件分支
switch 多條件分支 程式一開始先顯示訊息請使用者選擇季節, 然後讓使用者輸入代表季節的數字, 並且將該數字轉成整數之後放入 season 變數中, 最後使用 switch 敘述顯示適合於該季節的穿著。您可以看到, switch 敘述會依據 season 的值, 去執行對應 case 內的敘述。
break 敘述的重要性 break 是用來結束單一個 case, 如果不加上 break, 程式也能執行, 但是會發生程式繼續往下一個 case 對應的敘述執行的情況。例如:
break 敘述的重要性
break 敘述的重要性
break 敘述的重要性 由於 case 1 的敘述中沒有 break, 因此, 程式就會繼續執行第 22 行的程式, 直到遇到第 23 行的 break 才中斷。 雖然遺漏 break 可能會讓程式執行的結果錯誤, 但有些情況下不使用 break 卻可以縮短程式的長度, 請看以下這個範例:
break 敘述的重要性
break 敘述的重要性
break 敘述的重要性
break 敘述的重要性
break 敘述的重要性 由於漢堡餐及起司堡餐的價錢一樣, 因此我們故意拿掉 case 2 的敘述以及 break, 當使用者輸入 2 號餐時, switch 便會選擇第 22 行的 case 2 來執行, 由於 case 2 並無 break, 故程式繼續往下執行第 24 行的程式, 直到第 25 行的break 才中斷 switch 敘述。如果不這樣寫, 就得在第 22 行之後重複一段和第 24 ~ 25 一樣的程式。
捕捉其餘狀況的 default 在 switch 內還可以加上一個 default 敘述, 用來捕捉條件運算式與所有case 條件值都不相符的狀況, 就像是 else 用來捕捉所有的 if 條件都不成立的狀況一樣。語法如右:
捕捉其餘狀況的 default 以之前的點餐程式為例, 如果使用者輸入了非 1 ~ 4 的數值, switch 敘述並不會處理, 只會簡單的跳出 switch 敘述, 我們可以加上 default 來處理這樣的狀況:
捕捉其餘狀況的 default
捕捉其餘狀況的 default
捕捉其餘狀況的 default
捕捉其餘狀況的 default 這樣一來, 當使用者輸入的數值不符合可以點餐的數值時, 就會執行 default 條件的敘述, 顯示訊息告知使用者了。
5-4 綜合演練 判斷是否可為三角形三邊長 電影票票價計算 利用手機號碼前四碼判斷使用者使用的電信系統
判斷是否可為三角形三邊長 在學數學時曾學過, 三角形的兩邊長加起來一定大於第三邊, 我們可以應用這個定理寫一個測試三角形三邊長的程式, 如下:
判斷是否可為三角形三邊長
判斷是否可為三角形三邊長
判斷是否可為三角形三邊長
判斷是否可為三角形三邊長 程式一開始使用了之前提過的方式,讓使用者依序輸入三角形三個邊的邊長, 接著就利用了巢狀的三層 if 敘述判斷是否任兩邊的和都大於第三邊, 並且顯示適當的訊息。
電影票票價計算 電影院的售票, 通常會分為全票、早場票或軍警學生票等, 我們試著來開發一個售票亭使用的售票程式, 讓顧客在買票時可以挑選票種與張數, 並計算總金額:
電影票票價計算
電影票票價計算
電影票票價計算
電影票票價計算
電影票票價計算
電影票票價計算 程式一開始讓使用者輸入票種與票數, 然後利用一個 switch 敘述找出該票種對應的單價。由於一開始 ticket 的初值為 260, 也就是全票的價格, 所以若是使用者輸入了非 1~3 的數字, 就會被當成是全票。最後, 計算出票數乘上單價的總價, 顯示在螢幕上。
利用手機號碼前四碼判斷使用者使用的電信系統 用手機打電話給朋友時, 通常會考慮到網內網外費率的的問題, 可是我們通常都只有手機號碼, 要如何知道對方使用的系統呢?本節我們就來開發一個可以手機號碼前四碼判定使用者電信系統的程式:
利用手機號碼前四碼判斷使用者使用的電信系統
利用手機號碼前四碼判斷使用者使用的電信系統
利用手機號碼前四碼判斷使用者使用的電信系統
利用手機號碼前四碼判斷使用者使用的電信系統
利用手機號碼前四碼判斷使用者使用的電信系統 程式一開始先讓使用者輸入其電話號碼的前四碼, 然後將其轉為整數。要注意的是, 由於行動電話的頭一碼都是 "0", 因此轉為整數後頭一碼就消失了, 例如輸入 "0933", 轉成整數後為 933。接著, 程式就使用了一個多條件的if 敘述判斷所屬的系統商, 並顯示對應的訊息。
利用手機號碼前四碼判斷使用者使用的電信系統 這個程式看起來很複雜, 我們可以利用遺漏 break 的 case方式, 以 switch 改寫, 看起來會清楚簡單的多:
利用手機號碼前四碼判斷使用者使用的電信系統
利用手機號碼前四碼判斷使用者使用的電信系統
利用手機號碼前四碼判斷使用者使用的電信系統
利用手機號碼前四碼判斷使用者使用的電信系統
利用手機號碼前四碼判斷使用者使用的電信系統 程式中利用了不加上 break 時會連帶執行下一個 case 對應敘述的特性, 將同一系統門號的 case 項目集中, 執行同一個敘述顯示系統商名稱。這個技巧在某些時候非常有用, 可以多加變化應用。