今天寫代碼的時候,需要遍歷一個作為參數傳遞進來的容器,
當時順手就加上了判空條件:
if(null==list)return;
后來就像,不知道遍歷(foreach)有沒有幫我做這個工作:
下面看實驗結果:
public static void main(String[] args) { List<String> list =null; for (String s:list){ System.out.println(s); } }
運行時報空指針錯誤:
Exception in thread "main" java.lang.NullPointerException
at Test.main(Test.java:37)
說明在進行foreach遍歷的時候,需要判空的。
下面看看foreach到底是怎么實現的:
foreach是在jdk 1.5版本后推出更優雅的遍歷寫法:
jdk1.5之前:
遍歷數組:
1 for (int i=0;i<array.length;i++){ 2 //do something 3 }
遍歷容器:
while (list.iterator().hasNext()){ //do something }
jdk1.5之后:
for (String s:list){ //do something }
代碼看起來優雅了許多。
那foreach是一個新的東西么?相對於以前的的for循環來說,到底哪個效率要高一些呢?
下面看測試代碼:
List<String> list = new ArrayList<>(); String[] test = new String[]{}; //遍歷容器測試 public void collectionForeachTest() { for (String s : list) { //do something } } //循環容器測試 public void collectionIteatorTest() { Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { //do something } } //遍歷數組測試 public void arrayForeachTest() { for (String s : test) { //do something } } //循環數組測試 public void indexTest() { for (int i = 0; i < test.length; i++) { //do something } }
首先編譯。javap -c Test.class查看編譯源文件:
容器:使用遍歷和迭代器:
public void collectionForeachTest(); Code: 0: aload_0 1: getfield #4 // Field list:Ljava/util/List; 4: invokeinterface #7, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator; 9: astore_1 10: aload_1 11: invokeinterface #8, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z 16: ifeq 32 19: aload_1 20: invokeinterface #9, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object; 25: checkcast #5 // class java/lang/String 28: astore_2 29: goto 10 32: return public void collectionIteatorTest(); Code: 0: aload_0 1: getfield #4 // Field list:Ljava/util/List; 4: invokeinterface #7, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator; 9: astore_1 10: aload_1 11: invokeinterface #8, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z 16: ifeq 22 19: goto 10 22: return
數組:遍歷和索引:
public void arrayForeachTest(); Code: 0: aload_0 1: getfield #6 // Field test:[Ljava/lang/String; 4: astore_1 5: aload_1 6: arraylength 7: istore_2 8: iconst_0 9: istore_3 10: iload_3 11: iload_2 12: if_icmpge 26 15: aload_1 16: iload_3 17: aaload 18: astore 4 20: iinc 3, 1 23: goto 10 26: return public void indexTest(); Code: 0: iconst_0 1: istore_1 2: iload_1 3: aload_0 4: getfield #6 // Field test:[Ljava/lang/String; 7: arraylength 8: if_icmpge 17 11: iinc 1, 1 14: goto 2 17: return
可以看出來,總體來說:foreach就是iterator的語法糖,使用foreach,最后都會編譯成傳統的Iterator的方法。
結論:
1.使用foreach需要檢查對象是否為空,因為使用foreach相當於使用了obj.itreator()
2.foreach只是一個語法糖,使用foreach更安全(不會帶來數組越界的錯誤),但是最終編譯結果和以前的寫法是一樣的。