Java 中break和continue結合標籤標示符中斷迴圈示例詳解(附原始碼)
阿新 • • 發佈:2019-02-03
臭名昭著的goto
程式語言中一開始就有goto關鍵詞了。事實上,goto起源於組合語言的程式控制:“若條件A成立,則跳到這裡;否則跳到那裡”。如果閱讀由編譯器最終生成的彙編程式碼,就會發現程式控制裡包含了許多跳轉。(Java編譯器生成它自己的“彙編程式碼”,但是這個程式碼是執行在Java虛擬機器上的,而不是直接執行在CPU硬體上。) goto語句是在原始碼級上的跳轉,這使其招致了不好的聲譽。若一個程式總是從一個地方跳到另一個地方,還有什麼辦法能識別程式的控制流程呢?自從Edsger Dijkstra發表了著名論文《Goto considered harmful》(Goto標籤是什麼
儘管goto仍是Java中的一個保留字,但在語言中並未使用它;Java沒有goto。然而,Java也能完成一些類似於跳轉的操作,這與break和continue這兩個關鍵詞有關。它們其實不是一個跳轉,而是中斷迭代語句的一種方法。之所以把它們納入goto問題中一起討論,是由於它們使用了相同的機制:標籤。 標籤是後面跟有冒號的標示符,就像下面這樣:label1:
在Java中,標籤起作用的唯一的地方剛好是在迭代語句之前。“剛好之前”的意思表明,在標籤和迭代之間置入任何語句都不好。而在迭代之前設定標籤的唯一理由是:我們希望在其中巢狀另一個迭代或者一個開關。這是由於break和continue關鍵詞通常只是中斷當前迴圈,但若隨同標籤一起使用,它們就會中斷迴圈,直到標籤所在的地方:
在(1)中,break中斷內部迭代,回到外部迭代。在(2)中,continue使執行點移回內部迭代的起始處。在(3)中,continue label1同時中斷內部迭代及外部迭代,直接轉到label1處;隨後,它實際上是繼續迭代過程,但卻從外部迭代開始。在(4)中,break label1也會中斷所有迭代,並回到label1處,但並不重新進入迭代。也就是說,它實際是完全中止了兩個迭代。label1: outer-iteration{ inner-iteration{ //... break;//(1) //... continue;//(2) //... continue label1;//(3) //... break label1;//(4) } }
示例原始碼
下面是標籤用於for迴圈和while迴圈的例子:package com.mufeng.thefourthchapter;
public class Labeled {
public static void main(String[] args) {
System.out.println("標籤用於for迴圈的例子");
int i = 0;
outer: // Can't have statements here 這裡不能有陳述
for (; true;) {// infinite loop 無限迴圈
inner: // Can't have statements here 這裡不能有陳述
for (; i < 10; i++) {
System.out.println("i = " + i);
if (i == 2) {
System.out.println("continue");
continue;
}
if (i == 3) {
System.out.println("break");
i++;// Otherwise i never gets incremented 否則i不會得到增量
break;
}
if (i == 7) {
System.out.println("continue outer");
i++;// Otherwise i never gets incremented 否則i不會得到增量
continue outer;
}
if (i == 8) {
System.out.println("break outer");
break outer;
}
for (int k = 0; k < 5; k++) {
if (k == 3) {
System.out.println("continue inner");
continue inner;
}
}
}
}
System.out.println("標籤用於while迴圈的例子");
i = 0;
outer: while (true) {
System.out.println("Outer while loop");
while (true) {
i++;
System.out.println("i = " + i);
if (i == 1) {
System.out.println("continue");
continue;
}
if (i == 3) {
System.out.println("continue outer");
continue outer;
}
if (i == 5) {
System.out.println("break");
break;
}
if (i == 7) {
System.out.println("break outer");
break outer;
}
}
}
}
}
輸出結果
標籤用於for迴圈的例子
i = 0
continue inner
i = 1
continue inner
i = 2
continue
i = 3
break
i = 4
continue inner
i = 5
continue inner
i = 6
continue inner
i = 7
continue outer
i = 8
break outer
標籤用於while迴圈的例子
Outer while loop
i = 1
continue
i = 2
i = 3
continue outer
Outer while loop
i = 4
i = 5
break
Outer while loop
i = 6
i = 7
break outer
原始碼解析
注意,break會中斷for迴圈,而且在抵達for迴圈的末尾之前,遞增表示式不會執行。由於break跳過了遞增表示式,所以在i==3的情況下直接對i執行遞增運算。在i==7的情況下,continue outer語句會跳到迴圈頂部,而且也會跳過遞增,所以這裡也對i直接遞增。 如果沒有break outer語句,就沒辦法從內部迴圈裡跳出外部迴圈。這是由於break本身只能中斷最內層的迴圈(continue同樣也是如此)。 當然,如果想在中斷迴圈的同時退出,簡單地用一個return即可。 同樣的規則亦適用於while:- 一般的continue會退回最內層迴圈的開頭(頂部),並繼續執行。
- 帶有標籤的continue會到達標籤的位置,並重新進入緊接在那個標籤後面的迴圈。
- 一般的break會中斷並跳出當前迴圈。
- 帶標籤的break會中斷並跳出標籤所指的迴圈。