Java - Iterator 和 ListIterator

古古

2018/12/12


  • Iterator 是所有 Collection 類(List、Set….)們都可以使用的迭代器,而 ListIterator 則是專門為 List 類所設計的迭代器

    • Iterator 只支持 hasNext()next()remove() 三種操作,而 ListIterator 除了原本的 3 種之外,還支持了更多操作

      //Iterator接口
      public interface Iterator<E> {
          boolean hasNext();
          E next();
          void remove();
      }
      
      //ListIterator接口
      public interface ListIterator<E> extends Iterator<E> {
          //繼承自Iterator的接口
          boolean hasNext();         //後面是否有元素
          E next();                  //游標向後移動,取得後面的元素
          void remove();             //刪除最後一個返回的元素
      
          //ListIterator新增的接口
          boolean hasPrevious();     //前面是否有元素
          E previous();              //游標往前移動,取得前面的元素
          int previousIndex();       //取得游標前的index
          int nextIndex();           //取得游標後的index
          void set(E e);             //將當前元素改設成e
          void add(E e);             //增加一個元素
      }
      
  • Iterator 和 ListIterator 的差別

    • iterator() 方法在所有集合類中都能使用,但是 listIterator() 只有 List 類能用
    • Iterator 只能 remove() 元素,而 ListIterator 可以 add()set()remove()
    • Iterator 只能使用 next() 順序的向後遍歷,ListIterator 則向前 previous() 和向後 next() 遍歷都可以
      • 還有一個額外的功能,ListIterator 可以使用 nextIndex()previousIndex() 取得當前游標位置的前後 index 位置,Iterator 沒有此功能
  • 如果想在遍歷 List 時邊做刪除,用 Iterator 和 ListIterator 都能辦到,但如果是想在遍歷 List 時 add 元素,則只能使用 ListIterator 去做,因為 Iterator 是不提供此接口的

    • 要注意的是,邊遍歷 List 邊使用 Iterator 和 ListIterator 的 add()remove() 時,並不會影響當前 List 輸出結果,雖然他們修改的是同一個 List,但是迭代器故意將 add 和 remove 設計成就算執行了,也不影響當前迭代器的輸出結果

      public class Main {
          public static void main(String[] args) {
              List<Integer> list = new ArrayList<>();
              list.add(1);
              list.add(2);
              list.add(3);
      
              ListIterator<Integer> it = list.listIterator();
      
              while (it.hasNext()) {
                  Integer x = it.next();
                  System.out.println(x);
                  //雖然使用it.add(100)去新增一個元素,使得list實際儲存的是 [1,2,100,3]
                  //但是此處的遍歷仍然只顯示[1,2,3],這是迭代器故意這樣設計的
                  if (x == 2) {
                      it.add(100);
                  }
              }
      
              System.out.println("list: " + list);
          }
      }
      
      1
      2
      3
      list: [1, 2, 100, 3]
      
  • 另外,雖然 ArrayList 和 LinkedList 都支持 ListIterator,但通常只有在使用 LinkedList 時才會搭配 ListIterator

    • 因為 LinkedList 幾乎所有的時間消耗都是在去找到這個元素在哪,而找到此元素之後,對他進行修改是非常容易的事情(只要改指針就可以了),所以使用 ListIterator 的話,就可以節省下這個查找時間
    • 而對 ArrayList來說,因為他查找的速度很快(底層是數組),因此使用 ListIterator 省下的查找時間非常少,所以對他來說,並沒有迫切的需要使用 ListIterator,使用 add(index, E) 也能達到同樣的效率
    • 因此可以說 ListIterator 根本是為 LinkedList 發明的,ArrayList 只是順道實現而已,ArrayList 去實現只是為了設計成讓 List 接口的類們都能使用 ListIterator 而已