goto語句一直被人所詬病,說它使得代碼結構復雜化,但是語言設計者們還是沒有放棄goto這個功能強大的語句。Java以面向對象所著稱也沒能夠放棄goto,而是把它當做保留字,但是并未在語言中得到正式使用。
然而,從Java的break和continue這兩個關鍵字的身上,我們依然能夠看出一些goto的影子。
下面是《Thinking In Java 4th》中關于“goto”的介紹:
臭名昭著的“goto”
goto 關鍵字很早就在程序設計語言中出現。事實上,goto 是匯編語言的程序控制結構的始祖:“若條件A,則跳到這里;否則跳到那里”。若閱讀由幾乎所有編譯器生成的匯編代碼,就會發現程序控制里包含了許多
跳轉。然而,goto 是在源碼的級別跳轉的,所以招致了不好的聲譽。若程序總是從一個地方跳到另一個地方,還有什么辦法能識別代碼的流程呢?隨著Edsger Dijkstra 著名的“Goto 有害”論的問世,goto 便從此
失寵。
事實上,真正的問題并不在于使用goto,而在于goto 的濫用。而且在一些少見的情況下,goto 是組織控制流程的最佳手段。
盡管goto 仍是Java 的一個保留字,但并未在語言中得到正式使用;Java 沒有goto。然而,在break 和continue 這兩個關鍵字的身上,我們仍然能看出一些goto 的影子。它并不屬于一次跳轉,而是中斷循環語句的一種方法。之所以把它們納入goto 問題中一起討論,是由于它們使用了相同的機制:標簽。
Java中的標簽
“標簽”是后面跟一個冒號的標識符,就象下面這樣:
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 處,但并不重新進入循環。也就是說,它實際是完全中止了兩個循環。
代碼測試(java)
一下代碼均已在jdk1.6版本中測試通過
break語句測試
public static void testLabel()
{
for (int i = 0; i < 2; i++) {
System.out.println("L1----"+i);
for (int j = 0; j < 4; j++) {
if (j == 2) {
break;
}
System.out.println("--------L2---"+j);
}
}
}
執行結果:
L1----0
--------L2---0
--------L2---1
L1----1
--------L2---0
--------L2---1
這個代碼中break直接中斷內部的for循環。
break+label語句測試
public static void testLabel3()
{
label1:
for (int i = 0; i < 2; i++) {
System.out.println("L1----"+i);
for (int j = 0; j < 4; j++) {
if (j == 2) {
break label1;
}
System.out.println("--------L2---"+j);
}
}
}
執行結果:
L1----0
--------L2---0
--------L2---1
在這個代碼中break中斷標簽label1處的外部for循環。
continue語句測試
public static void testLabel2() {
for (int i = 0; i < 2; i++) {
System.out.println("L1----"+i);
for (int j = 0; j < 4; j++) {
if (j == 2) {
continue;
}
System.out.println("--------L2---"+j);
}
}
}
執行結果:
L1----0
--------L2---0
--------L2---1
--------L2---3
L1----1
--------L2---0
--------L2---1
--------L2---3
在這個代碼中continue中斷掉內部的for循環后繼續執行內部for循環。
continue+label語句測試
public static void testLabel4()
{
label1:
for (int i = 0; i < 2; i++) {
System.out.println("L1----"+i);
for (int j = 0; j < 4; j++) {
if (j == 2) {
continue label1;
}
System.out.println("--------L2---"+j);
}
}
}
執行結果:
L1----0
--------L2---0
--------L2---1
L1----1
--------L2---0
--------L2---1
在這個代碼中continue中斷掉內部的for循環后繼續執行跳到標簽label1處的外部for循環,繼續執行。