goto 關鍵字很早就在程序設計語言中出現。事實上,goto 是匯編語言的程序控制結構的始祖:“若條件 A,
則跳到這里;否則跳到那里”。若閱讀由幾乎所有編譯器生成的匯編代碼,就會發現程序控制里包含了許多
跳轉。然而,goto 是在源碼的級別跳轉的,所以招致了不好的聲譽。若程序總是從一個地方跳到另一個地
方,還有什么辦法能識別代碼的流程呢?隨著 Edsger Dijkstra 著名的“Goto 有害”論的問世,goto 便從此
失寵。
事實上,真正的問題并不在于使用 goto ,而在于 goto 的濫用。而且在一些少見的情況下,goto 是組織控制
流程的最佳手段。
盡管 goto 仍是 Java 的一個保留字,但并未在語言中得到正式使用;Java 沒有 goto 。然而,在 break 和
continue 這兩個關鍵字的身上,我們仍然能看出一些 goto 的影子。它并不屬于一次跳轉,而是中斷循環語
句的一種方法。之所以把它們納入 goto 問題中一起討論,是由于它們使用了相同的機制:標簽。
“標簽”是后面跟一個冒號的標識符,就象下面這樣:
label1:
對 Java 來說,唯一用到標簽的地方是在循環語句之前。進一步說,它實際需要緊靠在循環語句的前方——在
標簽和循環之間置入任何語句都是不明智的。而在循環之前設置標簽的唯一理由是:我們希望在其中嵌套另
一個循環或者一個開關。這是由于 break 和 continue 關鍵字通常只中斷當前循環,但若隨同標簽使用,它們
就會中斷到存在標簽的地方。如下所示:
label1:
外部循環{
內部循環{
//...
break; //1
//...
continue; //2
//...
continue label1; //3
//...
break label1; //4
}
}
在條件 1 中,break 中斷內部循環,并在外部循環結束。在條件 2 中,continue 移回內部循環的起始處。但
在條件 3 中,continue label1 卻同時中斷內部循環以及外部循環,并移至 label1 處。隨后,它實際是繼續
循環,但卻從外部循環開始。在條件 4 中,break label1 也會中斷所有循環,并回到 label1 處,但并不重
新進入循環。也就是說,它實際是完全中止了兩個循環。
下面是 for 循環的一個例子:
// : LabeledFor.java
// Java’s "labeled for loop"
public class LabeledFor {
public static void main(String[] args) {
int i = 0;
outer: // Can't have statements here
for (; true;) { // infinite loop
inner: // Can't have statements here
for (; i < 10; i++) {
prt("i = " + i);
if (i == 2) {
prt("continue");
continue;
}
if (i == 3) {
prt("break");
i++; // Otherwise i never
// gets incremented.
break;
}
if (i == 7) {
prt("continue outer");
i++; // Otherwise i never
// gets incremented.
continue outer;
}
if (i == 8) {
prt("break outer");
break outer;
}
for (int k = 0; k < 5; k++) {
if (k == 3) {
prt("continue inner");
continue inner;
}
}
}
}
// Can't break or continue
// to labels here
}
static void prt(String s) {
System.out.println(s);
}
}
這里用到了在其他例子中已經定義的 prt()方法。
注意 break 會中斷 for 循環,而且在抵達 for 循環的末尾之前,遞增表達式不會執行。由于 break 跳過了遞
增表達式,所以遞增會在 i==3 的情況下直接執行。在 i==7 的情況下,continue outer 語句也會到達循環頂
部,而且也會跳過遞增,所以它也是直接遞增的。
下面是輸出結果:
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
如果沒有 break outer 語句,就沒有辦法在一個內部循環里找到出外部循環的路徑。這是由于 break 本身只
能中斷最內層的循環(對于 continue 同樣如此)。
當然,若想在中斷循環的同時退出方法,簡單地用一個 return 即可。
下面這個例子向大家展示了帶標簽的 break 以及 continue 語句在 while 循環中的用法:
//: LabeledWhile.java//Java's "labeled while" loop
public classLabeledWhile {public static voidmain(String[] args) {int i = 0;
outer:while (true) {
prt("Outer while loop");while (true) {
i++;
prt("i = " +i);if (i == 1) {
prt("continue");continue;
}if (i == 3) {
prt("continue outer");continueouter;
}if (i == 5) {
prt("break");break;
}if (i == 7) {
prt("break outer");breakouter;
}
}
}
}static voidprt(String s) {
System.out.println(s);
}
}///:~
同樣的規則亦適用于 while:
(1) 簡單的一個 continue 會退回最內層循環的開頭(頂部),并繼續執行。
(2) 帶有標簽的 continue 會到達標簽的位置,并重新進入緊接在那個標簽后面的循環。
(3) break 會中斷當前循環,并移離當前標簽的末尾。
(4) 帶標簽的 break 會中斷當前循環,并移離由那個標簽指示的循環的末尾。
這個方法的輸出結果是一目了然的:
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
大家要記住的重點是:在 Java 里唯一需要用到標簽的地方就是擁有嵌套循環,而且想中斷或繼續多個嵌套級
別的時候。
在 Dijkstra 的“Goto 有害”論中,他最反對的就是標簽,而非 goto 。隨著標簽在一個程序里數量的增多,
他發現產生錯誤的機會也越來越多。標簽和 goto 使我們難于對程序作靜態分析。這是由于它們在程序的執行
流程中引入了許多“怪圈”。但幸運的是,Java 標簽不會造成這方面的問題,因為它們的活動場所已被限
死,不可通過特別的方式到處傳遞程序的控制權。由此也引出了一個有趣的問題:通過限制語句的能力,反
而能使一項語言特性更加有用。
---------------------
作者:淡紫色呼吸
來源:CSDN
原文:https://blog.csdn.net/jinghuayuanli/article/details/16844765