goto語句一直被人所詬病房揭,說它使得代碼結(jié)構(gòu)復(fù)雜化贤笆,但是語言設(shè)計(jì)者們還是沒有放棄goto這個(gè)功能強(qiáng)大的語句现斋。Java以面向?qū)ο笏Q也沒能夠放棄goto府树,而是把它當(dāng)做保留字俐末,但是并未在語言中得到正式使用。
然而奄侠,從Java的break和continue這兩個(gè)關(guān)鍵字的身上卓箫,我們依然能夠看出一些goto的影子。
下面是《Thinking In Java 4th》中關(guān)于“goto”的介紹:
臭名昭著的“goto”
goto 關(guān)鍵字很早就在程序設(shè)計(jì)語言中出現(xiàn)垄潮。事實(shí)上烹卒,goto 是匯編語言的程序控制結(jié)構(gòu)的始祖:“若條件A闷盔,則跳到這里;否則跳到那里”旅急。若閱讀由幾乎所有編譯器生成的匯編代碼逢勾,就會(huì)發(fā)現(xiàn)程序控制里包含了許多
跳轉(zhuǎn)。然而藐吮,goto 是在源碼的級(jí)別跳轉(zhuǎn)的溺拱,所以招致了不好的聲譽(yù)。若程序總是從一個(gè)地方跳到另一個(gè)地方谣辞,還有什么辦法能識(shí)別代碼的流程呢盟迟?隨著Edsger Dijkstra 著名的“Goto 有害”論的問世,goto 便從此
失寵潦闲。
事實(shí)上攒菠,真正的問題并不在于使用goto,而在于goto 的濫用歉闰。而且在一些少見的情況下辖众,goto 是組織控制流程的最佳手段。
盡管goto 仍是Java 的一個(gè)保留字和敬,但并未在語言中得到正式使用凹炸;Java 沒有g(shù)oto。然而昼弟,在break 和continue 這兩個(gè)關(guān)鍵字的身上啤它,我們?nèi)匀荒芸闯鲆恍ゞoto 的影子。它并不屬于一次跳轉(zhuǎn)舱痘,而是中斷循環(huán)語句的一種方法变骡。之所以把它們納入goto 問題中一起討論,是由于它們使用了相同的機(jī)制:標(biāo)簽芭逝。
Java中的標(biāo)簽
“標(biāo)簽”是后面跟一個(gè)冒號(hào)的標(biāo)識(shí)符塌碌,就象下面這樣:
label1:
對Java 來說,唯一用到標(biāo)簽的地方是在循環(huán)語句之前旬盯。進(jìn)一步說台妆,它實(shí)際需要緊靠在循環(huán)語句的前方——在標(biāo)簽和循環(huán)之間置入任何語句都是不明智的。而在循環(huán)之前設(shè)置標(biāo)簽的唯一理由是:我們希望在其中嵌套另
一個(gè)循環(huán)或者一個(gè)開關(guān)胖翰。這是由于break 和continue 關(guān)鍵字通常只中斷當(dāng)前循環(huán)接剩,但若隨同標(biāo)簽使用,它們就會(huì)中斷到存在標(biāo)簽的地方萨咳。如下所示:
label1:
外部循環(huán){
內(nèi)部循環(huán){
//...
break; //1
//...
continue; //2
//...
continue label1; //3
//...
break label1; //4
}
}
在條件1 中懊缺,break 中斷內(nèi)部循環(huán),并在外部循環(huán)結(jié)束某弦。在條件2 中桐汤,continue 移回內(nèi)部循環(huán)的起始處。但在條件3 中靶壮,continue label1 卻同時(shí)中斷內(nèi)部循環(huán)以及外部循環(huán)怔毛,并移至label1 處。隨后腾降,它實(shí)際是繼續(xù)循環(huán)拣度,但卻從外部循環(huán)開始。在條件4 中螃壤,break label1 也會(huì)中斷所有循環(huán)抗果,并回到label1 處,但并不重新進(jìn)入循環(huán)奸晴。也就是說冤馏,它實(shí)際是完全中止了兩個(gè)循環(huán)。
代碼測試(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);
}
}
}
執(zhí)行結(jié)果:
L1----0
--------L2---0
--------L2---1
L1----1
--------L2---0
--------L2---1
這個(gè)代碼中break直接中斷內(nèi)部的for循環(huán)寄啼。
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);
}
}
}
執(zhí)行結(jié)果:
L1----0
--------L2---0
--------L2---1
在這個(gè)代碼中break中斷標(biāo)簽label1處的外部for循環(huán)逮光。
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);
}
}
}
執(zhí)行結(jié)果:
L1----0
--------L2---0
--------L2---1
--------L2---3
L1----1
--------L2---0
--------L2---1
--------L2---3
在這個(gè)代碼中continue中斷掉內(nèi)部的for循環(huán)后繼續(xù)執(zhí)行內(nèi)部for循環(huán)。
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);
}
}
}
執(zhí)行結(jié)果:
L1----0
--------L2---0
--------L2---1
L1----1
--------L2---0
--------L2---1
在這個(gè)代碼中continue中斷掉內(nèi)部的for循環(huán)后繼續(xù)執(zhí)行跳到標(biāo)簽label1處的外部for循環(huán)墩划,繼續(xù)執(zhí)行涕刚。