3.8.2迴圈語句
3.8.2.1while語句
最近這些年買彩票只能去投注站買,早些年,筆者經常是在網上買。在網上買有個功能:追號。就是假如你想一直買同一組號碼,直到中大獎為止。你可以設定一個條件,比如中了頭獎就不繼續買了,如果沒有中頭獎,下一期繼續買同樣的號碼。對於這樣的功能,在程式中可以採用while迴圈來實現:
程式碼如下:
while(n<5000000) { System.out.println("下一期繼續買同一組號碼"); }
但是事實上,我們先要買第一期,然後才能判斷是否中頭獎,迴圈才能繼續:
程式碼如下:
do { System.out.println("買一組號碼"); } while (n < 5000000);
下面我們再用一個示例來解決我們兒子最近學奧數的一個數學問題,計算1+2+3+…+100;
int sum = 0;// 最終結果,初始為0 int add = 1;// 加數,初始為1 while (add <= 100) { sum = sum + add; add++;// 加完後,自增1 } System.out.println(sum);//最終結果是5050
通過上面例項我們知道,當while的條件為真,則執行迴圈語句。如果這個條件一直為真的話,程式就會進入一個死迴圈了。因此在實際程式編寫的時候,一定要保證這個條件隨著程式的執行,會在某一個時刻變為假,避免程式進入死迴圈。比如上面這個例子變數add會自增,所以一定大於100。
3.8.2.2for語句
對於上面這個數學問題,我們可以看出來,它的迴圈次數是固定的,對於這種迴圈問題,Java還有一種更加簡潔的語句來實現,就是for迴圈。程式碼可以寫成這樣:
int sum = 0;// 最終結果,初始為0 for (int add = 1; add <= 100; add++) { sum += add; } System.out.println(sum);// 最終結果是5050
我們可以看到,程式碼的第2行,把加數add的初始化、迴圈條件和add的自增都放到一行了,顯得更加簡潔。它的通用結構如下:
for(表示式1 ; 表示式2 ; 表示式3)
- 表示式1:一般用來初始化迴圈迭代計數器
- 表示式2:必須是一個結果為boolean的表示式,一般用作迴圈條件
- 表示式3:一般用來迭代迴圈計數器
其實對於for迴圈中括號內,是分成3個部分,每個部分之間用分號(;)隔開。Java允許這3個部分放置任何表示式,並且都是可以省略不寫的。示意圖如下:
另外,對於在表示式1中宣告的變數,它的作用域是整個for迴圈的迴圈體。對於在迴圈語句中定義的變數,作用域只能在迴圈體{}內。
有的時候,在一個for迴圈中,會有多個計數器,例如前面追號買彩票的例子,可以設定追號10期,但是有的時候你的賬戶餘額不足了,彩票站不會給你墊錢追號的,程式碼可以寫成這樣:
for (int balance = 10, count = 1; balance >= 2 && count <= 10; count++, balance -= 2) { System.out.println("餘額還剩" + balance + "元,購買第" + count + "期彩票"); }
balance:賬戶餘額;count:追號期數
執行結果:
餘額還剩10元,購買第1期彩票
餘額還剩8元,購買第2期彩票
餘額還剩6元,購買第3期彩票
餘額還剩4元,購買第4期彩票
餘額還剩2元,購買第5期彩票
我們可以看到:
- 表示式1可以同時定義多個同型別的變數(balance和count)
- 表示式2迴圈條件是餘額大於等於2(夠一張彩票錢)並且追號期數小於等於10(我們設定的期數)
- 表示式3可以同時對balance和count進行更新
雖然Java的語法規則對for迴圈的表示式1、表示式2、表示式3的限制非常少,但是筆者不建議編寫晦澀難懂的語句,儘量保證程式碼的可讀性。
3.8.2.3break
在上面這個例子中,程式碼其實寫的就有點晦澀,不易閱讀。對於餘額不足的情況,其實可以認為是中止迴圈的一個條件。我們可以用break來中止迴圈,程式碼可以改寫:
int balance = 10; for (int count = 1; count <= 10; count++) { System.out.println("餘額還剩" + balance + "元,購買第" + count + "期彩票"); balance -= 2; // 當餘額不足2元的時候,中止迴圈 if (balance < 2) { break; } }
在while中同樣可以使用break,我們將上面程式碼改寫成while版本:
int balance = 10; int count = 1; while (count <= 10) { System.out.println("餘額還剩" + balance + "元,購買第" + count + "期彩票"); count++; balance -= 2; // 當餘額不足2元的時候,中止迴圈 if (balance < 2) { break; } }
這2段程式碼的執行結果都是:
餘額還剩10元,購買第1期彩票
餘額還剩8元,購買第2期彩票
餘額還剩6元,購買第3期彩票
餘額還剩4元,購買第4期彩票
餘額還剩2元,購買第5期彩票
break關鍵字,只能中止當前迴圈,當有多個迴圈巢狀使用的時候,有時候想要直接中止最外層迴圈,對於這種需求,在C++中是使用goto關鍵字來實現的。我們在學習關鍵字的時候,發現Java將goto作為保留字了,但是卻沒有使用它,而是用了另外一種方法來實現。叫做帶標籤的break語句。
首先我們得想一個多層巢狀的例子,正當我冥思苦想的時候,突然發我兒子床頭的一張乘法口訣表:
假如我們用程式列印這張表,可以用到2層巢狀的迴圈語句。第一層迴圈列印每一行的所有算式,然後我們把列印每一行的功能也用一個迴圈來實現即第二層迴圈。程式碼如下:
// row是行號,一共需要列印9行 for (int row = 1; row <= 9; row++) { // column是列號,對於第row行,一共需要列印row列 for (int column = 1; column <= row; column++) { System.out.print(column + "×" + row + "=" + column * row + " "); } System.out.println();// 列印完一行,需要換行 }
執行結果如下:
1×1=1 1×2=2 2×2=4 1×3=3 2×3=6 3×3=9 1×4=4 2×4=8 3×4=12 4×4=16 1×5=5 2×5=10 3×5=15 4×5=20 5×5=25 1×6=6 2×6=12 3×6=18 4×6=24 5×6=30 6×6=36 1×7=7 2×7=14 3×7=21 4×7=28 5×7=35 6×7=42 7×7=49 1×8=8 2×8=16 3×8=24 4×8=32 5×8=40 6×8=48 7×8=56 8×8=64 1×9=9 2×9=18 3×9=27 4×9=36 5×9=45 6×9=54 7×9=63 8×9=72 9×9=81
Perfect!完美的列印出來了。假如我們想在列印到第8行第5列的時候,不想列印了,程式碼改成下面這樣:
// row是行號,一共需要列印9行 for (int row = 1; row <= 9; row++) { // column是列號,對於第row行,一共需要列印row列 for (int column = 1; column <= row; column++) { System.out.print(column + "×" + row + "=" + column * row + " "); if (row == 8 && column == 5) { break; } }
System.out.println();// 列印完一行,需要換行
}
但是這樣的結果如下:
1×1=1 1×2=2 2×2=4 1×3=3 2×3=6 3×3=9 1×4=4 2×4=8 3×4=12 4×4=16 1×5=5 2×5=10 3×5=15 4×5=20 5×5=25 1×6=6 2×6=12 3×6=18 4×6=24 5×6=30 6×6=36 1×7=7 2×7=14 3×7=21 4×7=28 5×7=35 6×7=42 7×7=49 1×8=8 2×8=16 3×8=24 4×8=32 5×8=40 1×9=9 2×9=18 3×9=27 4×9=36 5×9=45 6×9=54 7×9=63 8×9=72 9×9=81
雖然第8行第5列之後的沒有列印,但是第9行又列印出來了。我們再改成帶標籤的break。
1 print_row: // 這是一個標籤 2 for (int row = 1; row <= 9; row++) { 3 // column是列號,對於第row行,一共需要列印row列 4 for (int column = 1; column <= row; column++) { 5 System.out.print(column + "×" + row + "=" + column * row + " "); 6 if (row == 8 && column == 5) { 7 break print_row;// 中止標籤print_row 8 } 9 } 10 System.out.println();// 列印完一行,需要換行 11 }
執行結果:
1×1=1 1×2=2 2×2=4 1×3=3 2×3=6 3×3=9 1×4=4 2×4=8 3×4=12 4×4=16 1×5=5 2×5=10 3×5=15 4×5=20 5×5=25 1×6=6 2×6=12 3×6=18 4×6=24 5×6=30 6×6=36 1×7=7 2×7=14 3×7=21 4×7=28 5×7=35 6×7=42 7×7=49 1×8=8 2×8=16 3×8=24 4×8=32 5×8=40
這一次結果正確。我們在第1行新增一個標籤“print_row”,然後在第7行中止該標籤。這樣做相當於跳轉到標籤“print_row”標記的程式碼塊的末尾即第11行。需要注意的是,標籤後面需要緊跟一個冒號(:)。
3.8.2.4continue
在上面列印乘法口訣表的例子,假如我們不想列印第4行和第4列,想想有啥辦法嗎?我們可以想到,當列印到第4行的時候,直接換一行去列印第5行。當列印到第4列的時候,也跳過,然後去列印第5列。對於這種需求,我們可以用到continue語句。continue的作用就是跳過當前迴圈體中剩餘的部分,回到當前迴圈的首部。程式碼如下:
1 for (int row = 1; row <= 9; row++) { 2 /*第4行,列印換行,然後繼續列印下一行*/ 3 if (row == 4) { 4 System.out.println(); 5 continue; 6 } 7 for (int column = 1; column <= row; column++) { 8 /*第4列,打6個空格,然後繼續列印下一列*/ 9 if (column == 4) { 10 System.out.print(" "); 11 continue; 12 } 13 System.out.print(column + "×" + row + "=" + column * row + " "); 14 } 15 System.out.println(); 16 }
執行結果如下:
1×1=1 1×2=2 2×2=4 1×3=3 2×3=6 3×3=9 1×5=5 2×5=10 3×5=15 5×5=25 1×6=6 2×6=12 3×6=18 5×6=30 6×6=36 1×7=7 2×7=14 3×7=21 5×7=35 6×7=42 7×7=49 1×8=8 2×8=16 3×8=24 5×8=40 6×8=48 7×8=56 8×8=64 1×9=9 2×9=18 3×9=27 5×9=45 6×9=54 7×9=63 8×9=72 9×9=81
我們看到,結果第4行和第4列都空出來了。需要注意的是,continue只是跳過當前迴圈體的剩餘部分,如果是for迴圈,表示式3部分還是會執行的。
continue語句也可以帶標籤,作用是跳到與標籤匹配的迴圈首部(如果是for迴圈,則是表示式3)。我們看程式碼和結果:
print_row: for (int row = 1; row <= 9; row++) { for (int column = 1; column <= row; column++) { /*第4列,則直接列印下一行*/ if (column == 4) { System.out.println(); continue print_row; } System.out.print(column + "×" + row + "=" + column * row + " "); } System.out.println(); }
結果:
1×1=1 1×2=2 2×2=4 1×3=3 2×3=6 3×3=9 1×4=4 2×4=8 3×4=12 1×5=5 2×5=10 3×5=15 1×6=6 2×6=12 3×6=18 1×7=7 2×7=14 3×7=21 1×8=8 2×8=16 3×8=24 1×9=9 2×9=18 3×9=27