首頁  >  文章  >  Java  >  Java中關於迭代器的使用詳解

Java中關於迭代器的使用詳解

黄舟
黄舟原創
2017-09-23 10:13:241304瀏覽

這篇文章主要介紹了java 中迭代器的使用方法詳解的相關資料,希望透過本文能幫助到大家,需要的朋友可以參考下

java 中迭代器的使用方法詳解

前言:

 迭代器模式將一個集合給封裝起來,主要是為使用者提供了一種遍歷其內部元素的方式。迭代器模式有兩個優點:①提供給使用者一個遍歷的方式,而沒有暴露其內部實作細節;②把元素之間遊走的責任交給迭代器,而不是聚合對象,實現了使用者與聚合對象之間的解耦。

      迭代器模式主要是透過Iterator介面來管理一個聚合物件的,而使用者使用的時候只需要拿到一個Iterator類型的物件即可完成對該聚合物件的遍歷。這裡的聚合物件一般是指ArrayList,LinkedList和底層實作為陣列等擁有一組相同或相似特性的物件。透過迭代器模式對聚合物件的遍歷主要是透過Iterator介面的next(),hasNext()方法進行的,這裡next()方法將傳回目前遍歷點的元素值,而hasNext()方法則表徵目前遍歷點之後還有沒有元素。 Iterator介面中還有一個remove()方法,將移除目前遍歷點的元素。在一般情況下不需要使用該方法,一些特殊的情況可以呼叫該方法,如果當前聚合物件的遍歷不支援該操作,那麼可以在該方法中跑出UnSupportedOperationException。

      這裡我們以下列範例來說明迭代器模式。現有兩家餐廳的兩套菜單,一套菜單是使用陣列實現的,而另外一套菜單是使用ArrayList實現的。現在由於兩個餐廳的合併而需要將兩套菜單進行整合,由於雙方的廚師都已經習慣了各自的菜單組裝方式,因而都希望各自繼續維護各自的菜單樣式。但是,對於服務員來說,其為顧客提供菜單的時候則必鬚根據兩套菜單進行兩種不同方式的處理,這必然會增加服務員的工作難度,而且,如果後期有新的餐廳合併進來,比如其使用的菜單種類為HashMap,那麼服務生將又會維護這套菜單,這也不利於擴充。根據服務員的需求,其需要的是一個菜單列表,如果其面向的是各個不同的菜單類,那麼勢必會增加其工作難度,並且各個不同的菜單類中所提供的方法也不一定是服務員所需要的,因而,根據服務員的需求,這裡需要製定一個菜單的規範,以實現服務員能夠按照同一種方式對其進行遍歷。這裡就可以使用到迭代器模式,服務員只需要面向迭代器接口進行遍歷,而各個廚師所擁有的菜單只需要實現該迭代器即可,其依然可以按照各自的方式維護其菜單項目。這樣就實現了不同的菜單與服務生的解耦。以下是使用迭代器模式解決該問題的具體程式碼。

選單介面(主要包含建立迭代器的方法):


public interface Menu<T> {
  Iterator<T> createIterator();
}

選單項目:


##

public class MenuItem {
  private String name;
  private String description;
  private boolean vegetarian;
  private double price;

  public MenuItem(String name, String description, boolean vegetarian, double price) {
    this.name = name;
    this.description = description;
    this.vegetarian = vegetarian;
    this.price = price;
  }

  public String getName() {
    return name;
  }

  public String getDescription() {
    return description;
  }

  public boolean isVegetarian() {
    return vegetarian;
  }

  public double getPrice() {
    return price;
  }
}

選單類別(選單項目的組裝方式):

##

public class DinerMenu implements Menu<MenuItem> {
  private static final int MAX_ITEMS = 6;
  private int numberOfItems = 0;
  private MenuItem[] menuItems;

  public DinerMenu() {
    menuItems = new MenuItem[MAX_ITEMS];
    addItem("Vegetarian BLT", "(Fakin&#39;) Bacon with lettuce & tomato on whole wheat", true, 2.99);
    addItem("BLT", "Bacon with lettuce & tomato on whole wheat", false, 2.99);
    addItem("Soup of the day", "Soup of the day, with a side of potato salad", false, 3.29);
    addItem("Hotdog", "A hot dog, with saurkraut, relish, onions, topped with cheese", false, 3.05);
  }

  public void addItem(String name, String description, boolean vegetarian, double price) {
    MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
    if (numberOfItems >= MAX_ITEMS) {
      System.out.println("Sorry, menu is full, Can&#39;t add item to menu");
    } else {
      menuItems[numberOfItems] = menuItem;
      numberOfItems++;
    }
  }

  @Deprecated
  public MenuItem[] getMenuItems() {
    return menuItems;
  }

  public Iterator<MenuItem> createIterator() {
    return new DinerMenuIterator(menuItems);
  }
}
public class PancakeHouseMenu implements Menu<MenuItem> {
  private ArrayList<MenuItem> menuItems;

  public PancakeHouseMenu() {
    menuItems = new ArrayList<>();
    addItem("K&B&#39;s Pancake Breakfast", "Pancakes with scrambled eggs, and toast", true, 2.99);
    addItem("Regular Pancake Breakfast", "Pancakes with fried eggs, sausage", false, 2.99);
    addItem("Blueberry Pancakes", "Pancakes made with fresh blueberries", true, 3.49);
    addItem("Waffles", "Waffles, with your choice of blueberries or strawberries", true, 3.49);
  }

  public void addItem(String name, String description, boolean vegetarian, double price) {
    MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
    menuItems.add(menuItem);
  }

  @Deprecated
  public ArrayList<MenuItem> getMenuItems() {
    return menuItems;
  }

  public Iterator<MenuItem> createIterator() {
    return menuItems.iterator();
  }
}

迭代器介面:

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

迭代器類:

public class DinerMenuIterator implements Iterator<MenuItem> {
  private MenuItem[] items;
  private int position = 0;

  public DinerMenuIterator(MenuItem[] items) {
    this.items = items;
  }

  @Override
  public boolean hasNext() {
    return position < items.length && items[position] != null;
  }

  @Override
  public MenuItem next() {
    return items[position++];
  }

  @Override
  public void remove() {
    if (position <= 0) {
      throw new IllegalStateException("You can&#39;t remove an item until you&#39;ve done at least one next()");
    }

    if (items[position - 1] != null) {
      for (int i = position - 1; i < items.length - 1; i++) {
        items[i] = items[i + 1];
      }
      items[items.length - 1] = null;
    }
  }
}
public class PancakeHouseIterator implements Iterator<MenuItem> {
  private ArrayList<MenuItem> items;
  private int position = 0;

  public PancakeHouseIterator(ArrayList<MenuItem> items) {
    this.items = items;
  }

  @Override
  public boolean hasNext() {
    return position < items.size();
  }

  @Override
  public MenuItem next() {
    return items.get(position++);
  }
}

服務生類別:

public class Waitress {
  private Menu<MenuItem> pancakeHouseMenu;
  private Menu<MenuItem> dinerMenu;

  public Waitress(Menu<MenuItem> pancakeHouseMenu, Menu<MenuItem> dinerMenu) {
    this.pancakeHouseMenu = pancakeHouseMenu;
    this.dinerMenu = dinerMenu;
  }

  public void printMenu() {
    Iterator<MenuItem> pancakeIterator = pancakeHouseMenu.createIterator();
    Iterator<MenuItem> dinerIterator = dinerMenu.createIterator();
    System.out.println("MENU\n----\nBREAKFAST");
    printMenu(pancakeIterator);
    System.out.println("\nLUNCH");
    printMenu(dinerIterator);

  }

  private void printMenu(Iterator<MenuItem> iterator) {
    while (iterator.hasNext()) {
      MenuItem menuItem = iterator.next();
      System.out.print(menuItem.getName() + ", ");
      System.out.print(menuItem.getPrice() + " -- ");
      System.out.println(menuItem.getDescription());
    }
  }
}

      從上面的程式碼可以看出,服務生並沒有針對具體的選單進行編程,而是依賴一個創建選單迭代器的Menu介面和一個迭代器介面Iterator來進行編程的,服務生並不需要知道所傳過來的是何種組裝方式的選單,而只需要使用實現這兩個接口的菜單對象進行遍歷即可,這就達到了將變化的依賴於多態而實現接口,將不變的依賴於接口的目的,從而實現服務員與菜單組裝方式的分離。

      迭代器模式在Java類別庫的集合中隨處可見,這裡使用的Menu就相當於Java類別庫中的Iterable接口,其作用是創建一個迭代器對象,而Iterator接口和Java類庫的Iterator接口基本一致。這裡需要說明的是,實際上讓一個類別實現迭代器模式在為一個類別增加功能的同時也增加了該類別的維護負擔,因為類別的基本方法是高內聚的,所謂的內聚即是實現了一套相關的完整的功能,而迭代器介面其實也是一套完整的相關的功能,因而讓一個類別實作迭代器模式隱含地為這個類別增加了兩套不那麼「內聚」的兩套功能,這就會導致該類別在進行功能維護的時候需要兼顧雙方。在Java類別庫中ArrayList和LinkedList中就有體現,其不僅提供了List所有的基本的remove方法,也提供了迭代器所需實現的remove方法,為了實現兩者的統一,其不得不作一些約定,例如遍歷集合的時候不能呼叫該類別基本的remove或add等會更改該類別結構的方法。

以上是Java中關於迭代器的使用詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn