第 6 堂課 - 特定條件選擇與迴圈初探
上次更新日期 2018/08/11
雖然使用 if 選擇來進行條件判斷已經很好用了,不過, if 畢竟是每一個條件都需要去慢慢判斷,如果使用巢狀 if 的設定,光是看到好幾個 if, 可能會讓程式設計者或者是後來的維護者,覺得相當為難。那如果這些條件已經是很固定的項目,我們能不能使用比較簡單的方式來判斷呢? 有的!那就是透過 switch (交換) 來處理即可。另外,亂數的處理以及迴圈的設計,也是會使用到許多的條件判斷,這都是相當有趣的喔!
- 6.0: 英打練習與上週作業執行
- 6.1: 使用 swich 取代巢狀 if 的設計
- 6.2: 亂數的應用
- 6.3: 使用 while 迴圈
- 6.4: 課堂練習
- 6.5: 課後練習
6.0: 英打練習與上週作業執行
資訊科技的技術,如果不是老闆,生產力人員 (就是你我) 通常不會只使用手持式裝置,至少會使用到各式鍵盤。因此,打字就非常重要, 好的打字速度帶你上天堂,差的打字速度讓你呆成糖 (蟲的台語,慢吞吞之意)!關於打字練習的重要注意事項請參考第 0 堂課的說明, 同時,請花 10 分鐘完成第 0 堂課的英文打字練習。完成之後,請打開你的 notepad++ 軟體,輸入底下的字串喔!
import java.util.Scanner; ↵ public class unit06_4_2 { ↵ public static void main ( String args[] ) { ↵ Scanner input = new Scanner ( System.in ); ↵ String vbmesg = ""; ↵ System.out.print ("輸入 0, 1, 2, 3 (ex> 1): "); ↵ planet = input.nextInt(); ↵ if ( planet == 1 ) { ↵ radius = 6373; ↵ volume = 4 / 3 * 3.14159 * radius * radius * radius; ↵ vbmesg = "你想看地球: 半徑: " + radius + ", 體積為: " + volume; ↵ } else { ↵ vbmesg = "看屁啦!"; ↵ } ↵ System.out.println (vbmesg+"\n"); ↵ } ↵ } ↵
你不需要複製貼上,這單純是要讓你的打字速度變快!所以不要太緊張!練習就對了!沒練習完畢?沒關係,有空繼續練習即可!
- 上週作業的執行
請從 class.vbird.tw 上面下載你上週的作業 java 文字檔,然後先行編譯成功後,等待老師過來查閱是否編譯成功與執行成功! 若執行成功,在你的作業成績會打 v !
6.1: 使用 swich 取代巢狀 if 的設計
如果 if 內的條件判斷相當的單純,並不是一個範圍 (例如成績範圍之類的),而是單純的整數或者是字串時, 就可以使用 switch 來增加程式的可讀性與可維護性。那麼 switch 怎麼寫呢?基本的語法是這樣的:
switch (條件判定,通常是變數名稱) { case 條件值A : 處理程序 A1; 處理程序 A2; ...; break; case 條件值B : 處理程序 B1; ...; break; case 條件值C : 處理程序 C1; ...; break; default: 預設處理程序1; .... }
如上表所示,粗體字就是關鍵字,是不能改變的!所以,依據上面的說明,我們可以將上述的程式碼轉成中文的解釋是:
選擇項目 (變數的名稱) { 案例 變數值1 : 在 "變數名稱==變數值1" 這個情況下,所需要進行的程式碼 結束 (break) 這個案例 案例 變數值2 : 在 "變數名稱==變數值2" 這個情況下,所需要進行的程式碼 結束 (break) 這個案例 .... 預設動作 : 當變數的值跟上面的案例設定都不相同,就用這個區塊的程式碼 而且這樣就結束了,所以不需要 break 另外,順序是有差別的,所以 default 請一定放在最後面 } 結束這次的選擇 (switch)
基本上 switch 是用來作為多種固定的選擇條件底下,所進行的程式碼設計,因此單純的 if 就不需要使用 switch , 不過較多的選擇時,就建議使用這個項目!例如在 unit05_3_3.java 的情況底下,我們讓用戶選擇 1, 2, 3 這三個數值, 然後來給予不同形狀的面積計算,這樣就能夠使用 switch 的處理了!現在,請將 unit05_3_3.java 使用 switch 改寫一下, 改寫後的主程式 if 部份變成 switch 的項目會像這樣:
switch ( select ) { case 1: System.out.print ( "請輸入圓形的半徑: " ); radius = input.nextDouble(); area = 3.14159 * radius * radius; vbmesg = "您選擇圓型,輸入的半徑為 " + radius + " ,所以面積是: " + area; break; case 2: System.out.print ( "請輸入三角形的底長: " ); xline = input.nextDouble(); System.out.print ( "請輸入三角形的高: " ); yline = input.nextDouble(); area = xline * yline * 0.5; vbmesg = "您選擇三角形,輸入的底為 " + xline + " ,輸入的高為 " + yline + " ,所以面積是: " + area; break; case 3: System.out.print ( "請輸入矩形的底長: " ); xline = input.nextDouble(); System.out.print ( "請輸入矩形的高: " ); yline = input.nextDouble(); area = xline * yline ; vbmesg = "您選擇矩形,輸入的底為 " + xline + " ,輸入的高為 " + yline + " ,所以面積是: " + area; break; default: vbmesg = "喂, 喂, 不要亂選!臭小子!不理你了"; }
如上所示,沒有了 if, else if 的巢狀設計,全部都是同一層的 case 項目,因此在程式的觀察上面會比較輕鬆愉快些! 當然啦請設定完畢之後重複編譯與執行,這個程式要順利運作才行!在這樣的設計是較為單純簡易的。不過還是要強調的是, 在 switch 後面的小括號內,通常放的就是變數名稱,而 case 後面擺放的,就是變數的值。因此第一個 case 是 (select == 1) 的意思, 第二個 case 則是 (select == 2) 的意思,這樣就清楚多了吧!
- 解決午餐的問題
很多同學中午都不知道該吃什麼,光是選擇就覺得很頭痛~沒關係,我們可以用程式來解決這個問題。 請至少找到 5 間店家,然後使用 switch 來設定好店家的名稱。然後讓使用者在 1~5 之間隨意挑選,根據使用者的挑選, 來給予店家的店名。
- 分析問題:其實簡單到爆炸,就根據使用者的輸入結果來找到答案即可。
- 解決步驟:
- 匯入 java.util.Scanner 套件
- 宣告類別名稱為 unit06_1_2 (就是檔名)
- 開啟方法為 main 的程式
- 建立名為 input 的 Scanner 物件,同時以 nextInt() 取得使用者輸入的數值
- 以 switch 設定,來提供上述數值所對應的店家
- 透過 System.out.println 告知使用者中午可以前往的店家名稱
- 關閉 main
- 關閉類別
- 程式設計:
switch ( select ) { case 1: vbmesg = "絕鼎炒飯"; break; case 2: vbmesg = "正樽當歸鴨"; break; .... default: vbmesg = "喂, 喂, 不要亂選!臭小子!不理你了"; }
- 編譯、執行與測試:
C:\Users\dic\java>java unit06_1_2 請輸入 1~5 的整數,好決定中午應該吃啥? 3↵ 魚小璐 C:\Users\dic\java>java unit06_1_2 請輸入 1~5 的整數,好決定中午應該吃啥? 1↵ 絕鼎炒飯 C:\Users\dic\java>java unit06_1_2 請輸入 1~5 的整數,好決定中午應該吃啥? 7↵ 喂, 喂, 不要亂選!臭小子!不理你了
基本上,能達成任務的程式就是好程式,因此,不論是 if 還是 switch ,這邊只是講語法,這些語法能夠用上你的程式來達成任務, 那就是成功了!不必要非得使用 switch 或 if 不可喔!
6.2: 亂數的應用
剛剛 6.1 小節裡面,我們談到午餐的設計方式~問題是,如果每次都是同一個人來輸入,輸入過幾次之後,不就知道每個數值對應的店家了!? 這根本就是騙小孩的嘛!那怎辦?這個時候就得要用所謂的『亂數』來處理了。
所謂的『亂數』其實就是依據某些訊號來隨機給予的一個數值,這個數值在你每次觀察時,都可能會不一樣。這就有點像是丟骰子或者是銅板, 你每次丟的時候可能都不知道結果是什麼的意思。我們在之前曾經用過 System.currentTimeMillis() 函數來取得微秒數值, 這個數值隨時間而變,因為太小而且變化太快了,所以就成為一個亂數的使用來源。那有沒有專門產生亂數的亂數產生器呢? 有的!就透過 Math.random() 函數即可。
- Math.random() 的用法
當執行 Math.random() 時,它會產生一個 0.0~0.999... 之間的數值,亦即此數值為:
- 0 <= Math.random() < 1
這個數值永遠不會是 1 喔!要注意!要注意!因此,如果你需要產生一個 0~9 的亂數,就得要使用『 (int)(Math.random()*10) 』這樣的方式~ 如果要產生的是 1~10 呢?就會是『 (int)(Math.random()*10) + 1 』這樣的方式。那如果是某個範圍內的亂數呢? 舉例來說, 10~20 之間的亂數呢?可以使用底下的公式來求得:
- (int) (Math.random() * (Y - X + 1)) + X
- (int) (Math.random() * (20 - 10 + 1)) + 10
- Y 是較大的整數, X 是較小的整數之意。
- 嘗試丟銅板功能
如果只要兩個數值,亦即只要 0 跟 1 的數值,那就使用『 (int)(Math.random()*2) 』即可取得!現在,我們來處理丟銅板的程式碼看看! 假設程式一開始就會取得一個 0 或 1 的亂數,當為 0 的時候就顯示正面,當為 1 的時候就顯示數字 (一般銅板就是大頭跟字!)。 然後讓使用者猜到底電腦亂數取得的是正面還是反面這樣。
- 分析問題:讓使用者點選 YES 或 NO 比較簡單!所以,我們還是使用 JOptionPane.showConfirmDialog 來處理較佳。 然後透過上面的 Math.random() 來取得亂數的結果吧!最後用 if 分析一下到底是 0 還是 1 的結果即可。
- 解決步驟:
- 匯入 javax.swing.JOptionPane 套件
- 宣告類別名稱為 unit06_2_1 (就是檔名)
- 開啟方法為 main 的程式
- 開使用 Math.random() 取得一個 0 或 1 的亂數值,假設為 coin 這個整數型態的變數
- 透過 showConfirmDialog 讓使用者輸入 YES 或 NO
- 因為上面使用者點選 YES 為 0 而 NO 為 1 ,因此可以透過與 coin 的比對,來判斷兩者是否相同。
- 並且最終告知使用者選的是否正確。
- 關閉 main
- 關閉類別
- 程式設計:
int coin = (int)(Math.random()*2); int select = JOptionPane.showConfirmDialog(null, "程式已經丟了一個銅板,請問你覺得是正面還是反面?\n正面選 YES 反面選 NO 喔!", "投擲銅板的程式", JOptionPane.YES_NO_OPTION); String vbmesg = ""; if ( coin == 0 ) { vbmesg = "銅板是正面, "; } else { vbmesg = "銅板是反面, "; } if ( coin == select ) { vbmesg = vbmesg + "你答對了!不錯喔!"; } else { vbmesg = vbmesg + "你答錯了!逼逼逼!出局!!"; } JOptionPane.showMessageDialog(null, vbmesg, "投擲銅板的程式", JOptionPane.INFORMATION_MESSAGE);
- 編譯、執行與測試:開始測試執行流程。
在使用 Math.random() 的時候你一定要注意的,就是底下兩個寫法的結果會完全不一樣:
- (int) Math.random() * 10 (錯誤)
- (int) (Math.random() * 10) (正確)
上述兩條式子中,底下是對的,上面是錯的!因為 (int) 的優先順序比起四則運算還要高,所以第一條算式的結果,會永遠都是 0 !而第二條算式中, 因為我們先用括號將 Math.random()*10 先進行運算了,因此才會得到正確的亂數資料喔!千萬注意!千萬注意!
- 解決午餐的困擾
那麼能不能讓系統自己取得亂數後,幫我們解決一下午餐要吃什麼呢?可以的!請將剛剛 unit06_1_2.java 的程式翻出來, 然後修改讓使用者輸入的資料,我們使用 JOptionPane.showConfirmDialog 的圖形化界面處理,當使用者選擇 YES 時,就開始計算! 否則就直接忽略結束掉程式!
- 分析問題:其實就是改善了讓使用者輸入數值,讓電腦自己以亂數取得一個範圍內的數值即可!在本案例中,我們需要的數值是 1~5 喔!
- 解決步驟:
- 匯入 javax.swing.JOptionPane 套件
- 宣告類別名稱為 unit06_2_2 (就是檔名)
- 開啟方法為 main 的程式
- 開使用 Math.random() 取得一個 1~5 的亂數值,假設為 lunch 這個整數型態的變數
- 透過 showConfirmDialog 讓使用者輸入 YES 或 NO
- 因為上面使用者點選 YES 為 0 而 NO 為 1 ,使用 if 來處理,只有為 0 時,才開始計算!
- 計算結果並用 switch 去處理對應的午餐食堂是哪一家
- 並且最終告知使用者的午餐是啥!
- 關閉 main
- 關閉類別
- 程式設計:
int lunch = (int)(Math.random()*5)+1; int select = JOptionPane.showConfirmDialog(null, "是否需要這個程式告訴你今天最好吃什麼啊!?", "決定午餐的程式", JOptionPane.YES_NO_OPTION); String vbmesg = "午餐可以吃:"; if ( select == 0 ) { switch ( lunch ) { case 1: vbmesg = vbmesg + "絕鼎炒飯"; break; case 2: vbmesg = vbmesg + "正樽當歸鴨"; break; ... } } else { vbmesg = "不吃了嘛?好的!請離開!"; } JOptionPane.showMessageDialog(null, vbmesg, "決定午餐的程式", JOptionPane.INFORMATION_MESSAGE);
- 編譯、執行與測試:開始測試執行流程。
當你的店家越多時,只要在 switch 裡面增加更多的數量,同時將 Math.random() 後面乘上的個數增加到對應的數量, 就能夠搞定了!以後想不到要吃什麼的時候,就使用這個方式來處理吧!
有了這東西,未來直接用亂數,可以做很多事情啊!哈哈哈!
6.3: 使用 while 迴圈
某些時刻我們會需要將某件事情一直重複的進行,只是進行過程中,某幾個變數可能會持續的進行變化這樣, 這種動作就得要透過所謂的『迴圈』來達成了!也就是說:『迴圈是用來重複執行一段特定程式, 直到滿足某個條件為止』的狀態。
舉例來說,如果你想要從 1 加總到 100 的時候,當然可以使用最簡單的方法,就是 (1+100)*100/2 這樣的方式來處理, 如果想要讓系統持續不斷的增加,難道要寫 1+2+3+4+5+... 這樣嘛?真是沒效率!那怎辦?可以透過 i++ 累加 i 值, 然後用『 sum = sum + i++ 』來獲得累加值就可以了啊!
在這種情況下,當然最終將 sum 這個數值給它顯示出來,就可以得到正確的加總的答案,而不是透過數學方法簡化得到答案。 那麼最簡單的 java 迴圈是什麼呢?自然就是 while { ... } 這個玩意兒了!while 的中文是『當...的時候就...』的意思, 至於 java 的簡易語法是這樣的:
while ( 條件判斷 ) { 滿足條件判斷時,就會進行的程式碼部份; 滿足條件判斷時,就會進行的程式碼部份; .... }
轉成中文的簡單意思就是:
當 (這個條件式真的) 就進行 動作1 動作2 ... 結束
上面語法的意思是,如果條件失敗了,才會停止這個迴圈,否則就會變成七彩霓虹燈,轉啊轉不停...因此,你必須要在程式碼裡面藏一個可以停止的條件! 例如,我們上面談到的,要讓數值從 1+2+3+4...+100 的時候,就是要讓某個數值小於等於 100 才進行,然後用剛剛講的, 透過 sum = sum + i++ 來處理持續累加的數值!
- 分析問題:要從 1 累加到 100 的話,應該需要有兩個參數,一個是會從 1 變成 2 變成 3 的變數,以及一個 將 1 + 2 + 3 累加起來的變數,然後,最終的結果是輸出累加的變數,但是條件設定就得要使用第一個變數才行。
- 解決步驟:
- 宣告類別名稱為 unit06_3_1 (就是檔名)
- 開啟方法為 main 的程式
- 宣告兩個整數,一個是每次運作都會增加 1 的數值,假設為 i,一個是累加值,加設為 sum, 且 i 預設為 1 而 sum 預設為 0 才行。
- 開始 while 的迴圈,且條件限制為 i <=100 才進行,亦即當 i > 100 時,就會脫離迴圈的意思。
- 迴圈的內容很簡單,就是要讓 i 增加 1 而讓 sum 累加。因此單純使用 sum = sum + i++ 即可。
- 透過 System.out.println 輸出最終的 sum 結果
- 關閉 main
- 關閉類別
- 程式設計:
int sum = 0, i = 1; while ( i <= 100 ) { sum = sum + i++; } System.out.println ( "從 1 + 2 +...+100 的結果: " + sum );
- 編譯、執行與測試:執行的結果會有點像這樣:
C:\Users\dic\java>java unit06_3_1 從 1 + 2 +...+100 的結果: 5050
其實這個範例當中最重要的是那個 i 值,也就是 while 後面接的那個條件判斷 ( i <= 100 ),因為如果沒有該條件, 這個迴圈將無止盡的跑...直到數值溢位或者是電腦熱當或者是其他不知名的問題而導致程式中斷,所以,當你在寫迴圈時, 先想一想,這個迴圈會進行幾次?這個迴圈有沒有設定讓迴圈脫離的條件等。
- 持續午餐調查的迴圈
讓我們回到午餐的調查程式,也就是 unit06_2_2.java 那隻程式,無論使用者輸入 YES 或者是 NO,最終程式都只運行一次。 如果讓使用者持續的調查午餐的餐點,會是什麼情況呢?我們知道使用者如果選擇 YES 是回傳 0 啊,那麼當回傳值為 0 時, 就在輸出完畢午餐的調查後,持續讓使用者再次點選調查的 YES ,該如何處理呢?
- 分析問題:發現到共有兩行文字要輸出,而且是中文字,沒有其他計算式,所以可以單純使用螢幕輸出指令即可。
- 解決步驟:很簡單,就依序將兩行文字帶入程式碼當中輸出即可。
- 匯入 javax.swing.JOptionPane 套件
- 宣告類別名稱為 unit06_3_2 (就是檔名)
- 開啟方法為 main 的程式
- 設定名為 select 的整數型態變數,且預設值為 0 喔!
- 設定午餐變數為 lunch 的整數型態變數
- 使用 while 迴圈,且設定 select == 0 的時候才進行迴圈內的動作
- 開始用 Math.random() 取得一個 1~5 的亂數值,並將值設定給 lunch
- 透過 showConfirmDialog 讓使用者輸入 YES 或 NO
- 因為上面使用者點選 YES 為 0 而 NO 為 1 ,使用 if 來處理,只有為 0 時,才開始計算!
- 計算結果並用 switch 去處理對應的午餐食堂是哪一家
- 並且最終告知使用者的午餐是啥!
- 關閉 main
- 關閉類別
- 程式設計:與原本的程式比較,我們必須要將變數宣告抽出 while 之內,所以在 while 以前先宣告好變數,
才能夠避免重複宣告的問題~!
int lunch = 0, select = 0; String vbmesg = ""; while ( select == 0 ){ lunch = (int)(Math.random()*5)+1; select = JOptionPane.showConfirmDialog(null, "是否需要這個程式告訴你今天最好吃什麼啊!?", "決定午餐的程式", JOptionPane.YES_NO_OPTION); vbmesg = "午餐可以吃: "; if ( select == 0 ) { switch ( lunch ) { case 1: vbmesg = vbmesg + "絕鼎炒飯"; break; case 2: vbmesg = vbmesg + "正樽當歸鴨"; break; ... } JOptionPane.showMessageDialog(null, vbmesg, "決定午餐的程式", JOptionPane.INFORMATION_MESSAGE); } else { vbmesg = "不吃了嘛?好的!請離開!"; } } JOptionPane.showMessageDialog(null, vbmesg, "決定午餐的程式", JOptionPane.INFORMATION_MESSAGE);
- 編譯、執行與測試:跟之前一樣,只是選擇之後不會離開,會直接再請使用者輸入喔!
透過這個簡單的處理方式,我們就能夠持續的追蹤到底有幾家店啊!還有那家店出現的頻率比較高這樣。這就是 while 迴圈的最簡單用法!
6.4: 課堂練習
現在來練習底下的許多有趣的題目:
- 跟電腦比大小
過年的時候,有時長輩會玩骰盅。現在假設有三顆骰子,每個骰子都是六個面 (所以數值由 1~6),你骰一次對方骰一次,總點數大的就贏小的。 你可以先讓電腦算出 3 個亂數,然後顯示在使用者的視窗上,之後使用者按下 YES 之後,就由電腦再算出三個骰子數,然後兩者比大小。 最終回報誰贏誰輸即可。執行『 java unit06_4_1 』會有點像這樣:
- 反覆出現的訊息
在 unit05_planet.java 當中,使用者只能單純選擇 1, 2, 3,如果想要重複選擇觀看不同的星球資料, 就得要重新執行該程式。現在,請將該程式轉存成為 unit06_4_2.java,增加迴圈的控制,只有當選擇為 0 的時候,才會停止該程式的運作。 同時將 if 的選擇方式改以 switch 的模式來取代掉。當執行『 java unit06_4_2 』時,會有如下的結果:
C:\Users\dic\java>java unit06_4_2 你想知道的星球特性: 0. 離開程式, 1. 地球, 2. 火星, 3. 木星 輸入 0, 1, 2, 3 (ex> 1): 1↵ 你想看地球: 半徑: 6373.0, 體積為: 8.131698376925961E11 你想知道的星球特性: 0. 離開程式, 1. 地球, 2. 火星, 3. 木星 輸入 0, 1, 2, 3 (ex> 1): 2↵ 你想看火星: 半徑: 3390.0, 體積為: 1.2239075122820999E11 你想知道的星球特性: 0. 離開程式, 1. 地球, 2. 火星, 3. 木星 輸入 0, 1, 2, 3 (ex> 1): 0↵
6.5: 課後練習
請先查閱 1.3 小節的介紹,了解雲端系統的登入、繳交資料檔名等等的設計,然後再繼續底下的習題。 最終要上傳的檔案有:
- unit06-4070CXXX-你的名字.docx
- unit06_result.java (純文字檔)
- unit06_dice.java (純文字檔)
- unit06_bmi.java (純文字檔)
- 完成上課的習題內容回答:
- 假設我有一隻程式,名為 select_lunch.java,裡面有個使用者輸入的變數,為整數,名稱為 myselect 這樣, 你的選擇僅有 4 個,就是 1, 2, 3, 4 而已,那該如何使用 switch 撰寫主體程式碼?寫下 switch 的主要語法即可。
- 如果我想要取得一個 1~6 的亂數,那使用 Math.random() 函數時,應該如何設計?
- 假設我想要隨機 (亂數) 讓系統產生一個橋牌的牌色,該如何設計亂數?(亦即如何透過亂數取得每張牌?牌的數量?)
- 迴圈可以讓我們持續不斷的輸出每些訊息。請寫下迴圈的語法,讓你的螢幕可以連續輸出 100 到 1 之間的數字
- 用 switch 將成績分群。亦即,當你輸入成績 (0~100) 之後,程式會回答你的等級應該是多少分的意思。常見的分級是這樣的:
- A. 90 ~100
- B. 80 ~ 89
- C. 70 ~ 79
- D. 60 ~ 69
- F. 其他成績
- 骰子一般就是 1~6 之間的數值,先讓電腦計算出兩個骰子的分數,然後再讓使用者判斷是單數還是雙數,
如果是使用者判斷正確,就給予正確的回應,若錯誤,就跟他說,猜錯了!若使用『 java unit06_dice 』之後,會出現如下的樣子:
- 以 unit05_bmi.java 為主要依據,在計算完畢之後,再給予一個 showConfirmDialog 的視窗,請問使用者要不要持續計算?
當使用者需要執行時,就再 run 一次,否則就離開該程式段落。執行『 java unit06_bmi 』會有點像這樣: