71
本本本本 本本本本本本本 本本本本本本本本本本本本本本本本本本本本本本本本本本本 本本本本本 本本本 本本本本本本本本本本本 本本本本 本本本 本本本本本本本 本本 ()(),,、、( 本本本本本本本本本本本本本本本 80% 本本本本本本本本本本本本本本本 本本本本本本本本本本本本本本本本 本本本本本本本本本本本本本本本本本本 本本本本本本本本本 ),,、; 本本本本 本本本本本本本本本本本本本本本本 本本本本本本本本本本本本本本本本本本本本本本本本本本本本 ,,。 本本本本本 © 本本本本本本本本本本 本本本本 ( 本 ) 本本 本 6 本

SCJP ch06

Embed Size (px)

Citation preview

Page 1: SCJP ch06

本投影片(下稱教用資源)僅授權給採用教用資源相關之旗標書籍為教科書之授課老師(下稱老師)專用,老師為教學使用之目的,得摘錄、編輯、重製教用資源(但使用量不得超過各該教用資源內容之 80% )以製作為輔助教學之教學投影片,並於授課時搭配旗標書籍公開播放,但不得為網際網路公開傳輸之遠距教學、網路教學等之使用;除此之外,老師不得再授權予任何第三人使用,並不得將依此授權所製作之教學投影片之相關著作物移作他用。

著作權所有 © 旗標出版股份有限公司

流程控制 ( 二 ) :迴圈第 6 章

Page 2: SCJP ch06

2

學習目標

學習讓程式能夠重複執行的方法 學習控制程式執行次數的方法 了解何謂迴圈及認識各種迴圈的語法 學習跳出迴圈的方法

Page 3: SCJP ch06

3

前言 在第 5 章中 , 我們已充分練習了如何使用條件判斷來控制程式流程 , 本章我們要開始學習流程控制的另一把利器 ― 迴圈 (loop) 。

迴圈是用來解決重複性工作 ( 重複的執行動作 ) 的敘述。在日常生活中 , 往往我們都會為了一些例行性 (routine) 的工作浪費許多時間;辦公人員每天重複的收發表格、操作員重複地把原料放到機器上等。

Page 4: SCJP ch06

4

前言

這種重複性的工作即使是在寫程式時也很容易發生 ,

此時我們就需要利用迴圈來解決此類程式問題。 比如說我們要設計一個從 1 加到 100 的程式 , 並將累加的結果輸出到螢幕上 , 如果不使用迴圈 , 程式寫出來可能會像下面的樣子。

Page 5: SCJP ch06

5

前言

Page 6: SCJP ch06

6

前言

上列程式中 , 我們浪費太多的時間在撰寫重複的程式碼。如

果程式要算的是 1 加到 1000, 甚至 1 加到 100

00 呢?此時將耗費許多不必要的時間在程式撰寫上面。

為了改進重複性程式的撰寫或執行效率 , Java 提供了數種『迴圈』敘述 , 讓我們可大幅簡化重複性程式的撰寫。

Page 7: SCJP ch06

7

前言

迴圈其實是利用條件運算式的 true/false 來判斷是否要重複執行迴圈內的動作 , 當條件運算式為 true, 程式才會執行迴圈內的動作;條件運算式為 false 時 , 就會結束迴圈 ( 跳出迴圈 ), 然後繼續往下執行。如右圖:

因此當我們使用迴圈來解決上述 1 加到 100 的程式問題時 , 程式便會精簡許多 , 如下。

Page 8: SCJP ch06

8

前言

Page 9: SCJP ch06

9

前言

程式碼是不是精簡很多了呢?那是因為重複的程式碼被我們用迴圈取代了 , 只需寫一次即可 , 不必重複寫很多次 , 這就是迴圈的妙用。

其中 for 迴圈的用法我們會在下一節中詳細的說明。 在 Java 語言中 , 共有 for 、 while 及 do 三種迴圈敘述。以下我們將分別解說此三類迴圈並實際演練。▪ 單從寫程式的觀點 , 本就應熟悉各種迴圈的應用才能寫出有效率的程式 , 而應考 SCJP 時更是應將各種迴圈的寫法、結構、執行的流程了然於胸。

Page 10: SCJP ch06

10

6-1 for 迴圈

在前面的範例中 , 我們使用了 for 迴圈來計算 1

加到 100 的數值。 而 for 迴圈就是適用在需要精確控制迴圈執行次數的場合 , 像上述的例子 , 我們就是控制迴圈加到 10

0 就不要再執行了 , 此時程式便跳出迴圈。 以下就來說明 for 迴圈的語法。

Page 11: SCJP ch06

11

6-1-1 語法

for 迴圈的語法如下:

初始運算式:在第一次進入迴圈時 , 會先執行此處的運算式。在一般的情況下 , 我們都是在此設定條件運算式中會用到的變數之初始值。

Page 12: SCJP ch06

12

語法

條件運算式:用來判斷是否應執行迴圈中的動作敘述 ,

傳回值需為布林值。此條件運算式會在每次迴圈開始時都執行一次 , 以檢查讓迴圈執行的條件是否仍成立。比方說 , 條件運算式為 i < 10, 那麼只有在 i 小於 10 的情形下 , 才會執行迴圈內的動作敘述;一旦 i

大於或等於 10 時 , 迴圈便結束。

Page 13: SCJP ch06

13

語法 控制運算式:每次執行完 for 迴圈中的動作後 , 就會先

執行此運算式。此運算式通常都是用於調整條件運算式中會用到的變數值。以上例來說 , 在條件運算式為 i < 10 的情況下 , 要想讓此迴圈可以執行十次 , 就會在『初始運算式』設定 i=0, 再利用控制運算式來改變 i 值 , 例如 i++, 讓 i 以每次加 1 的方式不斷累加 , 等到 i 的值加到 10 的時候 , 條件運算式 i < 10 的結果即為 false, 此時迴圈結束 , 也完成我們想要迴圈執行 10 次的目標。

迴圈動作敘述:將您希望利用迴圈重複執行的敘述放在此處 , 如果要執行的敘述只有一個 , 也可省略前後的大括弧 {} 。

Page 14: SCJP ch06

14

語法 整個 for 迴圈的執行流程圖如右:

瞭解完語法後 , 以下進一步來控制運算式看 for 迴圈是怎麼執行的。

Page 15: SCJP ch06

15

6-1-2 執行流程

在上一小節中曾提及 , for 迴圈一般都是用一個變數來決定執行的次數 , 我們就以 for (i=0;i<3;i++) 這個迴圈為例 , 來看看 for 迴圈的執行步驟:

Page 16: SCJP ch06

16

執行流程

由上述例子可知 , 我們只要善用迴圈的條件運算式及控制運算式 , 就可以控制迴圈的執行次數。由此亦可得知 , 如果我們需要控制程式執行的次數 , for 迴圈將是最好的選擇。

我們實際以一個例子來作說明 , 假設要逐步計算某個範圍內 ( 例如 1 〜 1000) 所有奇數的總和 , 此時使用 for 迴圈來處理是最恰當的 , 程式碼如下。

Page 17: SCJP ch06

17

執行流程

Page 18: SCJP ch06

18

▪ 程式第 5 行、第 13〜 17 行有關讓使用者輸入所需的程式碼 , 請如前一章介紹的先依此形式直接使用 , 在第 14 、 16 章 , 才會說明這些程式碼的功用。

執行流程

Page 19: SCJP ch06

19

執行流程

在 for 迴圈的初始運算式中 , 也可以直接宣告新的變數來使用 , 例如上面程式中的 for(int i=1;...) 。

不過要特別注意 , 在 for 中宣告的變數就只能在 fo

r 迴圈中使用 , 例如:

Page 20: SCJP ch06

20

執行流程 另外 , 在初始運算式及控制運算式中也可以包含多個以逗號分隔的運算式 , 例如以下二種寫法都是允許的:

不過 , 在條件運算式中就只能有一個運算式 , 而且運算結果必須為 true 或 false 才行。

因此我們不可將『 i<5 && j>0 』寫成『 i<5 , j>0 』 , 當然也不可寫出像『 i=5 』這類運算結果不是布林值的式子 (應該用 == 而非 =) 。

Page 21: SCJP ch06

21

執行流程

最後 , for 迴圈的初始、控制、及條件運算式都不是必要的 , 若不需要可以省略 (雖然我們並不建議這樣做 ) 。

例如底下 3 個 for 敘述都是合法的:

Page 22: SCJP ch06

22

6-1-3 for-each 迴圈

for 還有一種另類的用法: for-each 迴圈 , 就是針對陣列 (詳見第 7 章 ) 或集合 (詳見第 18 章 ) 中的每一個元素 , 每次取出一個來進行迴圈處理。例如:

Page 23: SCJP ch06

23

for-each 迴圈

此處我們先簡單介紹 for-each 的用途 , 在第 7 、18 章還會有更詳細的說明。▪ 也有人將 for-each 稱做 for-in, 就是 for(i in a) 的意思。

Page 24: SCJP ch06

24

6-2 while 迴圈

while 迴圈的結構和前一章介紹的 if 條件判斷式看起來很類似 , 兩者都有個用括號括住的條件運算式 ,

加上一組由大括號括住的的動作敘述。 但兩者的差異在於: while 迴圈每次在執行完大括號中的動作敘述後 , 會跳回 while 的條件運算式再次檢查 , 如此反覆執行 , 直到條件運算式為 false

時才停止執行迴圈的動作。

Page 25: SCJP ch06

25

6-2-1 語法 while 迴圈有別於 for 迴圈的地方在於 , while 迴圈不需要初始算值及控制運算式 , 只需要條件運算式即可。如下述:

while :『當 . . 』 的意思。會根據條件式的真假 , 來決定是否執行迴圈內的動作。也就是說 『當條件式結果為真』 , 就執行迴圈內的動作的意思。若為假 , 則不予執行 ( 跳出迴圈 ) 。

條件運算式:可以是任何結果為布林值的運算式或布林變數。

Page 26: SCJP ch06

26

6-2-2 執行流程

看完如右的流程圖 , 應該不難發現 , 其實 while

迴圈的執行與 for 迴圈十分類似。

我們以上述計算奇數和的例子為藍圖 , 用 while

迴圈來改寫 , 並將奇數和改為偶數和 , 結果如下。

Page 27: SCJP ch06

27

執行流程

Page 28: SCJP ch06

28

執行流程

Page 29: SCJP ch06

29

執行流程 其中第 22 行的 i+=2; 有點類似 for 迴圈的控制運算式 , 讓 while 迴圈的條件運算式有可能產生 false 的結果。

如果把這行敘述拿掉 , while 迴圈內的條件運算式狀況將不會有所改變 (永遠是 true), 此時程式就會一直重複執行迴圈的敘述 , 而不會停下來 , 這種情況稱之為無窮迴圈。

假設我們要設計一個程式 , 計算 1 到 8 間 , 所有整數的和 , 而且在畫面上顯示從 1 開始加的時候 , 每一次累加的和。

如果使用 while 卻沒有敘述去改變條件運算式中用到的數值 , 就會發生計算結果不正確的情況。

Page 30: SCJP ch06

30

執行流程

Page 31: SCJP ch06

31

執行流程

Page 32: SCJP ch06

32

執行流程 我們可以發現這個程式有 2 個問題:

▪ 首先 , 我們希望程式算的是 0+1 、再加 2 、再加 3 的情形 , 但上列程式卻不是這樣加。

▪ 其次 , 這個迴圈會不停執行下去 , 因為 i 值恆等於 1, 自然永遠都小於使用者輸入的 range 指定數值 , 所以不會停止。

我們必須在程式第 24 行加入 "i++;" 或 "i+=1;" 的敘述:

Page 33: SCJP ch06

33

執行流程

加到後面 , i 值就會以累加 1 的方式不斷變動 , 最後當 i 值大於 8 時就會停止迴圈。

而且這樣一來 , 程式顯示的執行結果也會變得正確:

Page 34: SCJP ch06

34

6-3 do-while 迴圈 在三種迴圈方式裡 , do-while 迴圈算是 while 的一種變型 , 但它和 while 及 for 迴圈的執行流程上也有一些差異。

前面介紹的 for 及 while 迴圈通常被稱為『預先條件運算式』 迴圈。也就是說在執行迴圈之前 , 會預先檢查條件式是否為真 , 是的話才執行迴圈內的動作敘述。

do-while 迴圈則不同 , 在第一次進入迴圈時 , 不會先做任何檢查 , 而是先執行完迴圈內的動作敘述後 , 再檢查條件式是否成立 , 所以 do-while 迴圈的特點就是:不論條件式為何 , 迴圈敘述至少都會執行一次。

Page 35: SCJP ch06

35

6-3-1 語法

do-while 迴圈的結構像是個倒過來的 while 迴圈 ,

也就是把 "while ( 條件運算式 )" 這一段內容移到迴圈的最後面:

Page 36: SCJP ch06

36

6-3-2 執行流程

正如前面所提及的 , do-while 是先執行迴圈內的敘述再進行條件運算式判斷 , 因此其執行流程也稍稍有所不同 , 如右:

我們以一個實際的例子來測試 ,

就可以清楚的觀察到相同的程式因為執行流程上的不同 , 所產生的結果也會不同的情況 , 我們先用 while 迴圈來設計 , 如下。

Page 37: SCJP ch06

37

執行流程

Page 38: SCJP ch06

38

執行流程

此範例程式的 while 迴圈會在每次做完條件檢查時 ,

將 i 的值加 1, 結果使迴圈的敘述會執行 3 次。 接著用 do-while 來改寫同一個程式 , 如下:

Page 39: SCJP ch06

39

執行流程

如上 , 由於 i 是從 0 開始 , 且 do-while 會先執行完一次迴圈內的動作後 , 才進行檢查 , 使得這次迴圈的動作比前一個範例多執行 1 次。

讀者在設計程式時 , 可依程式的特性選用適當的迴圈敘述。

Page 40: SCJP ch06

40

6-4 巢狀迴圈

在上述的迴圈範例中 , 我們都是以一維的方式去思考 ,

比如說 1 加到 100, 只要一個累加變數就能解決問題。

但是如果要解決像九九乘法表這種二維的問題 (x,y

兩累加變數相乘的情況 ), 就必須將使用迴圈的方式做一些變化 , 也就是使用巢狀迴圈 (Nested loops) 。

巢狀迴圈就是迴圈的大括號之中 , 還有其它迴圈。例如 for 迴圈中還有 for 迴圈 , 或是 while 迴圈等。

以下就用實例來說明巢狀迴圈的應用。

Page 41: SCJP ch06

41

巢狀迴圈

Page 42: SCJP ch06

42

巢狀迴圈

Page 43: SCJP ch06

43

巢狀迴圈

在上述的例子中 , 我們利用兩個迴圈分別來處理九九乘法表的 (x, y) 變數的相乘動作。

當 x 等於 1 時 , 必須分別乘以 1 到 9 的 y ;當 x 等於 2 時 , 又是分別乘上 1 到 9

的 y..., 也就是在外部的 for

迴圈每執行一輪時 , 內迴圈就會執行 9 次 , 以此類推。執行流程如右圖:

Page 44: SCJP ch06

44

巢狀迴圈

Page 45: SCJP ch06

45

6-5 變更正常流程的 break 與 continue

有兩個敘述: break 及 continue, 都可以忽視迴圈正常的執行流程 , 而終止執行迴圈或跳出該輪迴圈。

Page 46: SCJP ch06

46

6-5-1 跳出一層迴圈的 break

如同 switch 多條件分支可以利用 break 敘述改變程式流程一樣 , 迴圈一樣有 break 敘述可以用來改變迴圈執行的流程。

迴圈中的 break 敘述 , 與 switch 的 break 敘述有相同的功能 , 它會中斷目前的迴圈執行 , 或者說是『跳出』迴圈。

寫過數個迴圈程式後 , 我們可以試著使用 break 來跳出迴圈:當程式中遇到某種狀況時 , 而不要繼續執行迴圈 , 即可用 break 來中斷迴圈 , 方法如下。

Page 47: SCJP ch06

47

跳出一層迴圈的 break

Page 48: SCJP ch06

48

跳出一層迴圈的 break

由於在第 7 行的條件運算式 "i > 0" 恆為真 , 所以會變成一個無窮迴圈。

不過由於程式在實際執行時 , i 變數會持續累加 , 等累加到 i 的值等於 5 時 , 第 9 行的 if 條件運算式其值為真 , 所以會執行 break 來跳出此層迴圈。

Page 49: SCJP ch06

49

6-5-2 結束這一輪迴圈的 continue

除了 break 敘述外 , 迴圈還有一個 continue 敘述 ,

continue 的功能與 break 相似 , 不同之處在於 br

eak 會跳出整個迴圈 , continue 僅跳出『這一輪』的迴圈 ,請看以下的程式範例。

Page 50: SCJP ch06

50

結束這一輪迴圈的 continue

Page 51: SCJP ch06

51

結束這一輪迴圈的 continue

執行結果獨缺了 5, 是因為第 5 圈時 , 在程式執行第 7 行的 continue 後 , 迴圈就被結束掉了 , 直接進行第 6 圈的迴圈 , 導致第 8 行敘述未被執行。

Page 52: SCJP ch06

52

6-5-3 標籤與 break/continue 敘述

如果程式中用的是巢狀迴圈 , 而您需要程式在某種狀況下 , 同時中止每一層的迴圈、或是同時中止該輪的內 / 外迴圈 , 用單純的 break/continue 敘述就顯得不方便了。

因為您必須在每一層的迴圈中 , 都加上 break/contin

ue 敘述 , 才能跳出迴圈或中止該輪的內 / 外迴圈。為解決這個問題 , Java 提供了另一種 break/continu

e 敘述的寫法 , 就是在 break/continue 敘述之後加上標籤 (Label) 。

Page 53: SCJP ch06

53

標籤與 break/continue 敘述

在迴圈敘述之前 , 可加上『標籤』來識別迴圈 , 其格式如右:

替迴圈加上標籤後 , 在內迴圈中都可在 break/contin

ue 敘述後加上該標籤名稱 , 表示要中斷的是指定標籤的迴圈 , 例如:

Page 54: SCJP ch06

54

標籤與 break/continue 敘述

此時 break 敘述不止會跳出最內層的 do 迴圈 , 也會跳出外層的 for 、 while 迴圈。

我們仍用前面的九九乘法表範例程式來說明 , 假設我們現在要讓 1〜 9 的乘法表中各只列出乘積小於或等於 25 的項目 , 此時可在內迴圈中檢查迴圈變數的乘積 , 大於 25 就中止該輪外迴圈 , 因此程式可改成如下。

Page 55: SCJP ch06

55

標籤與 break/continue 敘述

Page 56: SCJP ch06

56

標籤與 break/continue 敘述

Page 57: SCJP ch06

57

標籤與 break/continue 敘述

第 11 行的 if 敘述判斷 p 是否大於 25, 是就輸出換行字元 , 並於第 13 行用 "continue outloop;"

敘述中止這一輪的 outloop 迴圈 ( 第 7 行 ) 。 所以最後輸出的乘法表中 , 沒有乘積超過 25 的項目。

Page 58: SCJP ch06

58

6-A 迴圈與 if 條件式判斷式混合應用:取出 1 到指定 數值之間的質數

6-B 巢狀迴圈的應用:利用迴圈輸出等腰三角形圖案 6-C 各種迴圈的混合應用:計算階乘

Page 59: SCJP ch06

59

1. Given:

What is the result?

A. 27 B. 28 C. 29 D. 30 E. Compilation fails.

Page 60: SCJP ch06

60

2. Given :

What is the result? A. 3 B. 4 C. 5 D. 6 E. Compilation fails..

當答案中有編譯錯誤或執行錯誤的選項時 , 最好先檢查程式中是否有語法或邏輯錯誤 , 確定都沒錯之後 , 再去計算輸出值為何。

Page 61: SCJP ch06

61

▪ 當 s 為 null 時 , 執行 『 s == null 』 結果會是 tr

ue, 而執行 『 s.length() = 0 』 時則會造成錯誤。在第 4 行若將 | 改為短路的 ||, 則可以正確執行 , 並輸出 NULL 。

Page 62: SCJP ch06

62

3. What is the result of following program:

A. 012 B.01223 C.012233

D. 021323 E. 0213233 E.This program will not compile.

Page 63: SCJP ch06

63

Page 64: SCJP ch06

64

4. The following program is unable to compile:

Which two lines are causing the problem? A. L1 B. L2 C. L3 D. L4 E. L5 F. L6

Page 65: SCJP ch06

65

Page 66: SCJP ch06

66

5. Given:

Page 67: SCJP ch06

67

What is the result?A. 45x7

B. 45x877

C. 455x877

D. 345x

E. 3455x

F. 345x7

G. 3455x877

H. Compilation fails.

Page 68: SCJP ch06

68

6. Given:

Page 69: SCJP ch06

69

What is the result? A. DABCD

B. DEABCDE

C. EABCD

D. EABCDE

E. Compilation fails.

Page 70: SCJP ch06

70

7. Given:

Which two statements are true?A. The result is 23.

B. There is an infinitive loop in line 4-6.

C. i is 7 when the do loop is running over.

D. Compilation fails in line 1.

E. Compilation fails in line 4.

Page 71: SCJP ch06

71