1. 程式人生 > >Java 中break和continue結合標籤標示符中斷迴圈示例詳解(附原始碼)

Java 中break和continue結合標籤標示符中斷迴圈示例詳解(附原始碼)

臭名昭著的goto

       程式語言中一開始就有goto關鍵詞了。事實上,goto起源於組合語言的程式控制:“若條件A成立,則跳到這裡;否則跳到那裡”。如果閱讀由編譯器最終生成的彙編程式碼,就會發現程式控制裡包含了許多跳轉。(Java編譯器生成它自己的“彙編程式碼”,但是這個程式碼是執行在Java虛擬機器上的,而不是直接執行在CPU硬體上。)        goto語句是在原始碼級上的跳轉,這使其招致了不好的聲譽。若一個程式總是從一個地方跳到另一個地方,還有什麼辦法能識別程式的控制流程呢?自從Edsger Dijkstra發表了著名論文《Goto considered harmful》Goto
有害),眾人開始痛斥goto的不是,甚至建議將它從關鍵字集合中掃地出門。        對於這個問題,中庸之道是最好解決方法。真正的問題並不在於使用goto,而在於goto的濫用;而且少數情況下,goto還是組織控制流程的最佳手段。

標籤是什麼

      儘管goto仍是Java中的一個保留字,但在語言中並未使用它;Java沒有goto。然而,Java也能完成一些類似於跳轉的操作,這與breakcontinue這兩個關鍵詞有關。它們其實不是一個跳轉,而是中斷迭代語句的一種方法。之所以把它們納入goto問題中一起討論,是由於它們使用了相同的機制:標籤。        標籤是後面跟有冒號的標示符,就像下面這樣:
label1:

      在Java中,標籤起作用的唯一的地方剛好是在迭代語句之前。“剛好之前”的意思表明,在標籤和迭代之間置入任何語句都不好。而在迭代之前設定標籤的唯一理由是:我們希望在其中巢狀另一個迭代或者一個開關。這是由於breakcontinue關鍵詞通常只是中斷當前迴圈,但若隨同標籤一起使用,它們就會中斷迴圈,直到標籤所在的地方:
label1:
		outer-iteration{
			inner-iteration{
				//...
				break;//(1)
				//...
				continue;//(2)
				//...
				continue label1;//(3)
				//...
				break label1;//(4)
			}
		}
      在(1)中,break中斷內部迭代,回到外部迭代。在(2)中,continue使執行點移回內部迭代的起始處。在(3)中,continue label1同時中斷內部迭代及外部迭代,直接轉到label1處;隨後,它實際上是繼續迭代過程,但卻從外部迭代開始。在(4)中,break label1也會中斷所有迭代,並回到label1處,但並不重新進入迭代。也就是說,它實際是完全中止了兩個迭代。

示例原始碼

下面是標籤用於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會中斷並跳出標籤所指的迴圈。
        要記住的重點是:在Java裡需要使用標籤的唯一理由就是因為有迴圈巢狀存在,而且想從多層巢狀中breakcontinue