1. 程式人生 > >容器遍歷以及迭代器Iterator Iterable

容器遍歷以及迭代器Iterator Iterable

迭代器

提供一種方法對一個容器中的各個元素進行訪問,而又不暴露物件容器的內部細節。因為容器的內部結構不同,很多時候不知道該如何去遍歷一個容器中的元素,為了方便操作容器內元素,提供迭代器模式。

在這之前先重溫一下對於已知結構的容器的遍歷方式(傳統for迴圈)

陣列使用下標

for (int i = 0; i < array.length; i++) {
   System.out.println(array[i]);
}

List使用get(角標)方法

for(int i = 0 ; i < list.size() ; i++) {
  system.out.println(list.get(i));
}

那麼對於其他容器Set、Map容器內沒有角標,不能使用傳統for迴圈的或者其他不知道內部結構的容器,就需要使用迭代器或者基於迭代器實現的迭代方式。

迭代介面

Iterator介面

public interface Iterator<T>{ 
    boolean hasNext(); 
    AnyType next(); 
    void remove(); 
}

1 Java的Iterator的方法依賴當前位置,並且只能單向移動
2 使用hasNext()檢查序列中是否還有下一個元素
3 使用next()方法獲取序列的下一個元素
4 使用remove()方法將迭代器新進返回的元素刪除

Iterable介面

public interface Iterable<T> { 
     Iterator<T> iterator(); 
} 

1 Iterable介面中包含一個iterator()方法,該方法用來返回一個Iterator型別的物件(一個實現Iterator介面的物件)
2 Iterable介面被foreach用來在序列中移動,也就是說如果建立了實現Iterable介面的類,就可以將他應用在foreach語句中
3 Collection物件全部實現了Iterable介面,與foreach一起工作是Collection物件的共性

Iterable和Iterator的關係

1 首先Iterable的實現在於通過iterator方法獲取一個Iterator例項

2 Iterator物件一經建立,只能單向運動,這將意味著如果在其他的位置還要遍歷一遍容器則需要再建立一個Iterator物件,這也是Iterable介面做的事情,每次呼叫iterator()方法便返回一個新的從頭開始的Iterator迭代器,各個迭代器之間互不影響。

3 兩者不是隻能選擇一種實現的關係,而是相輔相成的,實現Iterator介面重新next()等方法對容器內部結構遍歷,實現terable介面,每次呼叫iterator()方法都返回一個新物件。

    如果我們需要為類A實現一個自定義的迭代器,首先要 
    a. 定義一個AIterator類實現Iterator介面,重寫next()等方法
    b. 在類A中實現Iterable介面,重寫iterator()方法
        public Iterator<T> iterator(){
            return new AIterator();
        }
    這兩者相輔相成,這也是很多地方說,Iterator是迭代類(實現一個基礎的迭代類),Iterable是迭代介面的原因

我們現在知道了兩個介面,一個負責底層邏輯,一個提供操作入口,不存在任何比較關係,那現在就來看看如何使用吧

1 使用iterator方法獲取一個Iterator物件並返回序列的第一個元素
2 使用hasNext()檢查序列中是否還有下一個元素
3 使用next()方法獲取序列的下一個元素
4 使用remove()方法將迭代器新進返回的元素刪除,這個刪除是作用在容器自身的,會刪除掉容器內的元素

這裡對這些方法有一點注意的

        Iterator iterator1 = list.iterator();
        Iterator iterator2 = list.iterator();
        //呼叫iterator()返回新的迭代器
  List<Integer> list = Arrays.asList(new Integer[]{1,2,3,4,5});
        Iterator iterator = list.iterator();
        while(iterator.hasNext()) {
            if(!iterator.next().equals(5)){
                System.out.println(iterator.next());
            }
        }
     //此處輸出2
     //因為我們再if(!iterator.next().equals(5))以及呼叫了一次iteartor.next()迭代器已經前進一位
     //再輸出iteartor.next()又前進一位,輸出2
     //iterator.next()是動態的,並不是在一次遍歷中就固定不動代表一個元素的
     //如果需要判斷輸出,要拿變數儲存
      List<Integer> list = Arrays.asList(new Integer[]{1,2,3,4,5});
        Iterator iterator = list.iterator();
        while(iterator.hasNext()) {
            Integer i = (Integer) iterator.next();
            if(!i.equals(5)){
                System.out.println(i);
            }
        }
        //輸出1
List<Integer> list = new ArrayList<Integer>(Arrays.asList(new Integer[]{1,2,3,4,5}));
        System.out.println(list);
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Integer i = (Integer) iterator.next();
            if(i.equals(3)){
              iterator.remove();
            }
        }
        System.out.println(list);
        //輸出:[1, 2, 3, 4, 5]
        //      [1, 2, 4, 5]
        //remove方法是作用的容器本身的

如何自定義一個迭代器

1 定義一個AIterator類實現Iterator介面,重寫next()等方法
 private class AIterator implements Iterator<T>{
        public boolean hasNest(){
            xxxx;
        }
        public T  next() {
           xxx;
        }
        public void remove() {
           xxx;
        }
    }
2 在類A中實現Iterable介面,重寫iterator()方法
public class A implements Iterable<T> {
      public Iterator<T> iterator(){
        return new AIterator();
    }
}

Collection集合中基於迭代器的遍歷方法

Collection中通用的迭代器遍歷 和 foreach

Iterator iterator = list.iterator();
while(iterator.hasNext()){
    int i = (Integer) iterator.next();
    System.out.println(i);
}
for (Object object : list) { 
    System.out.println(object); 
}

集合中其他遍歷方法

List

1 基於角標的get方法(不是迭代器實現的),只是在這裡提醒自己一下

Set

無,就是迭代器 + foreach

Map

Map是基於鍵值對的,所以它的迭代器實現比較特殊
就算使用迭代器通用方法也要先通過Map.entrySet拿出所有的鍵值對
Map類提供了一個稱為entrySet()的方法,這個方法返回一個Map.Entry例項化後的物件集,可以得到Map中所有的資料資訊。

1 非entrySet,一次一次get(key)
for (Integer in : map.keySet()) { //map.keySet(); //得到所有key的集合
    String str = map.get(in);//得到每個key多對用value的值
}
2 非entrySet + foreach遍歷value,但是不能得到可以值
for (String v : map.values()) {//map.values(); //得到所有value的集合
    System.out.println("value= " + v);
}
3 entrySet + Iterator
Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
     Map.Entry<Integer, String> entry = it.next();
     System.out.println( entry.getKey() + entry.getValue());
}
4 entrySet + foreach(推薦 尤其是資料大時)
for (Map.Entry<Integer, String> entry : map.entrySet()) {
    System.out.println(entry.getKey() + entry.getValue());
}