什麼swtich中case沒有break不行?
前言
一個小姐姐拿著一個switch的選擇題來問我。
之所以這麼篤定地回答這個問題,並不是我知道其中原理,而是之前在一個群裡,有人問了同類型的問題,我瞥了一眼記住了答案,所以才依葫蘆畫瓢。
小姐姐接著問我為什麼,我說少個break,但凡再問一句:為什麼少個break結果就不一樣,我就回答不出來了。所以,為了將尷尬扼殺於搖籃,還是研究一下break在switch的作用。
從位元組碼出發
按照慣例,先寫demo表述問題。
public static void main(String[] args) { int i = 0; switch (i) { case 0: System.out.println(0); case 1: System.out.println(1); case 2: System.out.println(2); }
執行程式碼,結果如下:
*明明只匹配了case 0,為什麼1和2也執行了? 很費解!按照慣用套路,看看位元組碼能不能給個答案。
javac編譯和javap檢視:
tableswitch和lookupswitch都用於switch條件跳轉,前者用於case值連續,例如上面程式碼中的0、1、2;後者用於case值不連續。
從位元組碼可以看出:switch中的case條件和對應程式碼塊是分開的。如上圖,case為0時,跳轉到標號28程式碼處;為1時跳轉到標號35程式碼處;為2時跳轉到標號43程式碼處;default則跳轉到標號49程式碼處。
這不,答案就出來了,當case 0匹配了之後,直接跳轉到標號28程式碼處開始執行,輸出0,然後策馬奔騰,一路小下坡,順序執行完後面所有程式碼,直到標號49 return,方法完執行完成,程式結束。
如果按照正常的思維,是不是case 0匹配之後,跳到28,執行完28、31、32輸出0之後,就應該直接跳走,直接執行49。那麼,這個”跳走”用位元組碼應該怎麼表示?
用return?那不行,因為return會結束方法,這樣switch後代碼也無法執行。那怎麼辦嘞….
關於goto
goto:無條件跳轉,goto 1表示跳轉到標號1的程式碼處。
再寫程式碼樣例,這次在程式碼中給每個case都加上break。
public static void main(String[] args) { int i = 0; switch (i) { case 0: System.out.println(0); break; case 10: System.out.println(1); break; case 2: System.out.println(2); break; } System.out.println("Hello World"); }
重新編譯,再來看看位元組碼。
如圖,與第一次的位元組碼相比,在標號35、45都有了goto指令。如果case 0匹配成功,則跳到標號28執行,執行完程式碼塊對應的31、32指令之後,執行35的goto指令跳轉到標號55,這樣就跳出了switch作用範圍,case 1和2也不會被執行。
等等,怎麼少了一個goto,在標號55的上方應該還有一個goto才對!其實這就涉及到了編譯器優化技術,最後一個goto也是跳轉到標號55的指令,但沒有goto下一步也一樣順序執行此行指令,所以這個goto被編譯器視為無用程式碼進行了消除。