開發與維運

集合輸出 | 帶你學《Java語言高級特性》之一百零六

上一篇:TreeSet子類排序操作 | 帶你學《Java語言高級特性》之一百零五
【本節目標】
本節需要掌握集合輸出的四種形式:Iterator迭代輸出、ListIterator雙向迭代輸出、Enumeration枚舉輸出、foreach輸出。

集合輸出

集合輸出實際上從JDK1.8開始就在Iterable接口中提供了一個forEach()方法,但是這種方法輸出並不是傳統意義上集合輸出形式,並且也很難在實際的開發之中出現,對於集合操作而言,一共有四種輸出形式:Iterator迭代輸出(95%)、ListIterator雙向迭代輸出(0.1%)、Enumeration枚舉輸出(4.9%)、foreach輸出(與Iterator相當)。

Iterator迭代輸出

通過Collection接口的繼承關係可以發現,從JDK1.5開始其多繼承了一個Iterable父接口,並且在這個接口裡面定義有一個iterator()操作方法,通過此方法可以獲取Iterator接口對象(在JDK1.5之前,這一方法直接定義在Collection接口之中)。

獲取Iterator接口對象:public Iterator<T> iterator​();

在Iterator接口裡面定義有如下的方法:

No. 方法名稱 類型 描述
01 public boolean hasNext​() 普通 判斷是否有數據
02 public E next​() 普通 取出當前數據
03 default void remove​() 普通 刪除

在之前使用的java.util.Scanner類就是Iterator接口的子類,所以此時類繼承關係如下:

image.png
Iterator接口

範例:使用Iterator輸出

import java.util.Set;
import java.util.Iterator;
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        Set<String> all = Set.of("Hello", "World", "MLDN");
        Iterator<String> iter = all.iterator();   //實例化Iterator接口對象
        while (iter.hasNext()) {
            String str = iter.next();
            System.out.println(str);   // World Hello MLDN
        }
    }
}

但是對於Iterator接口中的remove()方法的使用需要特別注意一下(如果不是必須不要使用)。實際上在Collection接口中定義有數據的刪除操作方法,但是在進行迭代輸出的過程中如果你使用了Collection中的remove()方法會導致迭代失敗。
範例:採用Collection集合中remove()方法刪除

import java.util.Set;
import java.util.Iterator;
import java.util.HashSet;
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        Set<String> all = new HashSet<String>();
        all.add("Hello");
        all.add("World");
        all.add("MLDN");
        Iterator<String> iter = all.iterator();   //實例化Iterator接口對象
        while (iter.hasNext()) {
            String str = iter.next();
            if ("World".equals(str)) {
                all.remove("World");  //Collection集合方法
            }else {
                System.out.println(str);   //  Hello   Exception in thread "main" java.util.ConcurrentModificationException
            }
        }
    }
}

此時無法進行數據刪除處理操作,那麼就只能夠利用Iterator接口中的remove()方法刪除。

範例:使用Iterator接口刪除方法

import java.util.Set;
import java.util.Iterator;
import java.util.HashSet;
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        Set<String> all = new HashSet<String>();
        all.add("Hello");
        all.add("World");
        all.add("MLDN");
        Iterator<String> iter = all.iterator();   //實例化Iterator接口對象
        while (iter.hasNext()) {
            String str = iter.next();
            if ("World".equals(str)) {
                iter.remove("World");  //Collection集合方法
            }else {
                System.out.println(str);   //  Hello   Exception in thread "main" java.util.ConcurrentModificationException
            }
        }
        System.out.println("*** "+ all);  
    }
}
//Hello
//MLDN
//*** [Hello, MLDN]

此時程序執行後沒有出現任何的錯誤,並且可以成功的刪除原始集合中的數據。
面試題:
請解釋Collection.remove()與Iterator.remove()的區別?
在進行迭代輸出的時候,如果使用了Collection.remove()則會造成併發更新的異常,導致程序刪除出錯,而此時只能夠利用Iterator接口中remove()方法實現正常的刪除處理。

ListIterator雙向迭代輸出

使用Iterator進行的迭代輸出操作有一個特點:只允許由前向後輸出,而如果現在需要進行雙向迭代處理,那麼就必須依靠Iterator的子接口:ListIterator接口來實現了。需要注意的是,如果想要獲取ListIterator接口對象,Collection中並沒有定義相關的處理方法,但是List子接口有,也就是說這個輸出的接口是專門為List集合準備的。

image.png
ListIterator接口

ListIterator接口中定義有如下的操作方法:

判斷是否有前一個元素:public boolean hasPrevious()
獲取當前元素:public E previous()

範例:實現雙向迭代

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        List<String> all = new ArrayList<String>();
        all.add("Hello");
        all.add("World");
        all.add("MLDN");
        ListIterator<String> iter = all.listIterator();
        System.out.print("由前向後輸出:");
        while (iter.hasNext()) {
            System.out.print(iter.next() + "、");
        }
        System.out.print("\n由後向前輸出:");   //由前向後輸出:Hello、World、MLDN、
        while (iter.hasPrevious()) {
            System.out.print(iter.previous() + "、");  //由後向前輸出:MLDN、World、Hello、
        }      
    }
}

如果想實現由後向前的遍歷,那麼首先要實現的是由前向後實現遍歷處理。

Enumeration輸出

Enumeration是在JDK1.0的時候就使用的輸出接口,這個輸出接口主要是為了Vector類提供服務的,一直到後續的JDK的發展,Enumeration依然只為Vector一個類服務,所以要想獲取Enumeration接口對象,那麼必須依靠Vector類提供的方法:

獲取Enumeration:public Enumeration<E> elements()
在Enumeration接口中定義有兩個操作方法:
判斷是否有下一個元素:public boolean hasMoreElements()
獲取當前元素:public E nextElement()

image.png
Enumeration

範例:使用Enumeration實現輸出

import java.util.Enumeration;
import java.util.Vector;
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        Vector<String> all = new Vector<String>();
        all.add("Hello");
        all.add("World");
        all.add("MLDN");
        Enumeration<String> enu = all.elements();
        while (enu.hasMoreElements()) {
            String str = enu.nextElement();
            System.out.print(str +"、");    //Hello、World、MLDN、
        }
    }
}

由於該接口出現的時間比較長了,所以在一些比較早的開發過程中,也有部分的方法只支持Enumeration輸出操作,但隨著類方法的不斷完善,大部分的操作都能直接利用Iterator實現了。

foreach輸出

除了使用迭代接口實現輸出之外,從JDK1.5開始加強型for循環也可以實現集合的輸出了。這種輸出的形式與數組的輸出操作形式類似。
範例:使用foreach輸出

import java.util.ArrayList;
import java.util.List;
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        List<String> all = new ArrayList<String>();
        all.add("Hello");
        all.add("World");
        all.add("MLDN");
        for (String str : all){
            System.out.print(str+"、");   //Hello、World、MLDN、
        }     
    }
}

這種輸出最初出現時很多人並不建議使用,因為標準的集合操作還是以Iterator為主,但是畢竟JDK1.5都已經推出十多年了,很多語法也開始被大部分人所習慣。

想學習更多的Java的課程嗎?從小白到大神,從入門到精通,更多精彩不容錯過!免費為您提供更多的學習資源。
本內容視頻來源於阿里雲大學

更多Java面向對象編程文章查看此處

Leave a Reply

Your email address will not be published. Required fields are marked *