<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ## [臭名昭著的 goto](https://lingcoder.gitee.io/onjava8/#/book/05-Control-Flow?id=%e8%87%ad%e5%90%8d%e6%98%ad%e8%91%97%e7%9a%84-goto) [**goto**關鍵字](https://en.wikipedia.org/wiki/Goto)很早就在程序設計語言中出現。事實上,**goto**起源于[匯編](https://en.wikipedia.org/wiki/Assembly_language)(assembly language)語言中的程序控制:“若條件 A 成立,則跳到這里;否則跳到那里”。如果你讀過由編譯器編譯后的代碼,你會發現在其程序控制中充斥了大量的跳轉。較之匯編產生的代碼直接運行在硬件 CPU 中,Java 也會產生自己的“匯編代碼”(字節碼),只不過它是運行在 Java 虛擬機里的(Java Virtual Machine)。 一個源碼級別跳轉的**goto**,為何招致名譽掃地呢?若程序總是從一處跳轉到另一處,還有什么辦法能識別代碼的控制流程呢?隨著*Edsger Dijkstra*發表著名的 “Goto 有害” 論(*Goto considered harmful*)以后,**goto**便從此失寵。甚至有人建議將它從關鍵字中剔除。 正如上述提及的經典情況,我們不應走向兩個極端。問題不在**goto**,而在于過度使用**goto**。在極少數情況下,**goto**實際上是控制流程的最佳方式。 盡管**goto**仍是 Java 的一個保留字,但其并未被正式啟用。可以說, Java 中并不支持**goto**。然而,在**break**和**continue**這兩個關鍵字的身上,我們仍能看出一些**goto**的影子。它們并不屬于一次跳轉,而是中斷循環語句的一種方法。之所以把它們納入**goto**問題中一起討論,是由于它們使用了相同的機制:標簽。 “標簽”是后面跟一個冒號的標識符。代碼示例: ~~~ label1: ~~~ 對 Java 來說,唯一用到標簽的地方是在循環語句之前。進一步說,它實際需要緊靠在循環語句的前方 —— 在標簽和循環之間置入任何語句都是不明智的。而在循環之前設置標簽的唯一理由是:我們希望在其中嵌套另一個循環或者一個開關。這是由于**break**和**continue**關鍵字通常只中斷當前循環,但若搭配標簽一起使用,它們就會中斷并跳轉到標簽所在的地方開始執行。代碼示例: ~~~ label1: outer-iteration { inner-iteration { // ... break; // [1] // ... continue; // [2] // ... continue label1; // [3] // ... break label1; // [4] } } ~~~ **\[1\]****break**中斷內部循環,并在外部循環結束。**\[2\]****continue**移回內部循環的起始處。但在條件 3 中,**continue label1**卻同時中斷內部循環以及外部循環,并移至**label1**處。**\[3\]**隨后,它實際是繼續循環,但卻從外部循環開始。**\[4\]****break label1**也會中斷所有循環,并回到**label1**處,但并不重新進入循環。也就是說,它實際是完全中止了兩個循環。 下面是**for**循環的一個例子: ~~~ // control/LabeledFor.java // 搭配“標簽 break”的 for 循環中使用 break 和 continue public class LabeledFor { public static void main(String[] args) { int i = 0; outer: // 此處不允許存在執行語句 for(; true ;) { // 無限循環 inner: // 此處不允許存在執行語句 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++; // 否則 i 永遠無法獲得自增 // 獲得自增 break; } if(i == 7) { System.out.println("continue outer"); i++; // 否則 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; } } } } // 在此處無法 break 或 continue 標簽 } } ~~~ 輸出結果: ~~~ 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**會中斷**for**循環,而且在抵達**for**循環的末尾之前,遞增表達式不會執行。由于**break**跳過了遞增表達式,所以遞增會在`i==3`的情況下直接執行。在`i==7`的情況下,`continue outer`語句也會到達循環頂部,而且也會跳過遞增,所以它也是直接遞增的。 如果沒有**break outer**語句,就沒有辦法在一個內部循環里找到出外部循環的路徑。這是由于**break**本身只能中斷最內層的循環(對于**continue**同樣如此)。 當然,若想在中斷循環的同時退出方法,簡單地用一個**return**即可。 下面這個例子向大家展示了帶標簽的**break**以及**continue**語句在**while**循環中的用法: ~~~ // control/LabeledWhile.java // 帶標簽的 break 和 conitue 在 while 循環中的使用 public class LabeledWhile { public static void main(String[] args) { int 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; } } } } } ~~~ 輸出結果: ~~~ 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 ~~~ 同樣的規則亦適用于**while**: 1. 簡單的一個**continue**會退回最內層循環的開頭(頂部),并繼續執行。 2. 帶有標簽的**continue**會到達標簽的位置,并重新進入緊接在那個標簽后面的循環。 3. **break**會中斷當前循環,并移離當前標簽的末尾。 4. 帶標簽的**break**會中斷當前循環,并移離由那個標簽指示的循環的末尾。 大家要記住的重點是:在 Java 里需要使用標簽的唯一理由就是因為有循環嵌套存在,而且想從多層嵌套中**break**或**continue**。 **break**和**continue**標簽在編碼中的使用頻率相對較低 (此前的語言中很少使用或沒有先例),所以我們很少在代碼里看到它們。 在*Dijkstra*的**“Goto 有害”**論文中,他最反對的就是標簽,而非**goto**。他觀察到 BUG 的數量似乎隨著程序中標簽的數量而增加\[^2\]。標簽和**goto**使得程序難以分析。但是,Java 標簽不會造成這方面的問題,因為它們的應用場景受到限制,無法用于以臨時方式傳輸控制。由此也引出了一個有趣的情形:對語言能力的限制,反而使它這項特性更加有價值。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看