發現
今天在探秘線程池原理知識點,在閱讀JDK源碼時遇到程序代碼中出現如下代碼,因為之前沒有遇到過,於是特地記錄下來並谷歌了一番,后面我自己做了一些簡要的驗證和分析。

驗證
網上溜達一番發現,這retry就是一個標記,標記對一個循環方法的操作(continue和break)處理點,功能類似於goto,所以retry一般都是伴隨着for循環出現,retry:標記的下一行就是for循環,在for循環里面調用continue(或者break)再緊接着retry標記時,就表示從這個地方開始執行continue(或者break)操作,具體我們來看看下面的例子:
1、使用continue跳出循環的操作:
1 public static void testContinue() { 2 retry: 3 for(int i = 0; i < 3; i++) { 4 for(int j = 0; j < 5; j++) { 5 System.out.print(j + ", "); 6 if(j == 3) { 7 continue retry; 8 } 9 } 10 } 11 System.out.print(" >>> OK"); 12 } 13 // 輸出:0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, >>> OK
2、使用breank跳出循環的操作:
1 public static void testBreak() { 2 retry: 3 for(int i = 0; i < 3; i++) { 4 for(int j = 0; j < 5; j++) { 5 System.out.print(j + ", "); 6 if(j == 3) { 7 break retry; 8 } 9 } 10 } 11 System.out.print(" >>> OK"); 12 } 13 // 輸出:0, 1, 2, 3, >>> OK
從上面的兩個例子可以看出,在內層循環里面調用continue(或者break)后接着retry標識符,程序直接轉到最外層for循環去處理了。
揭秘
我多想了一下,這個retry標記的使用原理是什么樣的?於是我扒了扒上面程序的反編譯代碼,希望能夠從中找到答案:
1 public static void testContinue() 2 { 3 for (int i = 0; i < 3; i++) { 4 for (int j = 0; j < 5; j++) 5 { 6 System.out.print(j + ", "); 7 if (j == 3) { 8 break; 9 } 10 } 11 } 12 System.out.print(" >>> OK"); 13 } 14 15 public static void testBreak() 16 { 17 for (int i = 0; i < 3; i++) { 18 for (int j = 0; j < 5; j++) 19 { 20 System.out.print(j + ", "); 21 if (j == 3) { 22 break label59; 23 } 24 } 25 } 26 label59: 27 System.out.print(" >>> OK"); 28 }
很明顯,編譯的時候編譯器自動按照程序邏輯轉換成了我們日常使用的方式來處理,比如continue的語句則翻譯成了break,而下面的break方法同樣使用了標記位,只是順序不同了而已,這和程序執行的邏輯順序應該是有關系的,顯然編譯器很聰明,如果你不加for循環下面的那一個關於OK的打印語句,編譯器就直接把break retry;轉換成了return;語句,說明編譯器已經知道在這里根據邏輯來判斷和處理了。
啟發
這一個標記的作用,給了我們一點點啟發,因為平時好像都沒有怎么見到過這個使用方法,但是類似跳出多重循環的場景卻不在少數,看看以前我們都是怎么樣處理的。
1、跳出里面的for循環,繼續從外面for循環開始執行:
1 public static void testContinueR() { 2 for(int i = 0; i < 3; i++) { 3 for(int j = 0; j < 5; j++) { 4 System.out.print(j + ", "); 5 if(j == 3) { 6 break; 7 } 8 } 9 } 10 }
使用break直接結束里面這一層循環,然后從外出for循環繼續開始。
2、跳出里外兩層循環,直接往下執行邏輯:
1 public static void testBreakR() { 2 boolean flag = false; 3 for(int i = 0; i < 3; i++) { 4 for(int j = 0; j < 5; j++) { 5 System.out.print(j + ", "); 6 if(j == 3) { 7 flag = true; 8 break; 9 } 10 } 11 if(flag) { 12 break; 13 } 14 } 15 System.out.println(" >>> OK"); 16 }
其實這里有兩種情況,如果for循環后面沒有內容了,可以直接在最里層循環執行return語句,如果后面還有其他邏輯執行,那么可以使用標記位輔助。
總結
如果你現在積累到了這個retry標記的用法,這個地方就可以更加靈活的處理了,可以不用寫那么多的輔助代碼,還有一點需要提一下,其實這個retry標識符不是指定的,只要任意符合Java變量命名的標識符都可以,只要后面接上英文冒號就行了。
1 public static void testOtherFlag() { 2 abc: 3 for(int i = 0; i < 3; i++) { 4 for(int j = 0; j < 5; j++) { 5 System.out.print(j + ", "); 6 if(j == 3) { 7 break abc; 8 } 9 } 10 } 11 } 12 13 // 輸出:0, 1, 2, 3,
其實和goto有同樣爭議的是,在過於復雜的循環程序里面使用這個標記,可能會降低程序的可讀性,所以在使用之前,還是需要自己權衡。
