條件語句是我們使用非常頻繁的語法之一,其中if-else和switch-case最為常用,那很多同學也會有疑惑,這兩種方式有什麼區別,哪個效率更高一些呢。接下來我們就從字節碼的角度,看看這兩種方法的實現。
先來看看if-else。
從代碼字面上理解,應該是自上而下,以此判斷,那到底是不是呢,看看字節碼。
iload_1將變量(i)推至棧頂,iconst_1將第一個整型常量(1)推至棧頂。
然後通過if_icmpne來判斷這兩個值是否相等,如果相等,就執行列印,然後跳轉到第42行,結束(下同),如果不相等,就跳轉至第15行。15行這次是取出第二個常量(2)去和 i 做比較,如果不相等,跳轉至第30行,取出第三個數值(3)去和 i 做比較,如果不相等,跳轉到第42行,結束。
從字節碼看,確實if-else是順序判斷,直到找到符合條件的。
那switch-case又是怎樣工作的呢?
先大概講一下,switch-case會創建一個table,每條case的值,作為key,對應著這個條件要跳轉到的指令行。
table有兩種,tableswitch和lookupswitch,每個條件的值之間的比較連貫的,會使用tableswitch,否則會使用lookupswitch,而且lookupswitch會對所有的case的值進行排序,保證是有序的,這樣可以提高查找效率。
接下來看例子。
1,2,4,6這是四種條件分支,不連續,但是間隔較小,所以JVM會使用tableswitch,看看字節碼是什麼樣。
先看看tableswitch的內容,我們發現,比我們的四種數據多了兩種,把1~6之間的缺少的值,補充了進去,形成一個連續的表。它們對應的指令行都是80,那第80行是什麼呢?其實就是default語句那一個分支。因為補充的這兩個在代碼中是不存在的,所以就讓它指向default就行了。
當判斷時,系統會判斷你輸入的值是否在1~6之間,如果不在,就直接跳到default,如果在,那就定位就好了,所以需要是一個連續的table。table中每一個數值後面對應這要跳轉到的指令行,根據key取到行號,跳就是了。
40,50,60,70分別對應這每個條件的列印代碼,執行完後,跳轉到87(return)。
下面我們把條件的值改一下,讓它的間隔大一些。
我們的順序是10,50,30,看看字節碼。
系統使用了lookupswitch,而且,它的排序是10,30,50,是按照升序排列的,變成了有序的。也沒有像tableswitch那樣,填充間隔,所以它們的查找方式是不一樣的。
因為是有序的,所以可以採取諸如二分法的算法,來提高查找效率。
理解力兩種條件語句的實現方式,那麼該如何選擇呢?
如果條件簡單而且比較少if-else也沒問題,畢竟switch-case要生成一個table,佔用了一定的空間,如果條件多,if-else不但不美觀,而且順序執行的效率也是比較低的。所以這時候採用switch-case是合理的。