Java Iterable- und Iterator-Schnittstelle

Eine der am weitesten verbreiteten und gebräuchlichsten APIs in Java ist der Iterator für die Sammlungen. Wenn wir die Liste der Objekte in einem Array haben oder Objekte auflisten, ist der Iterator sehr nützlich, um die Objekte ohne viel zusätzlichen Programmieraufwand zu iterieren. Hier diskutieren wir anhand einfacher Beispiele den Vergleich zweier wichtiger Schnittstellen, Iterable und Iterator.

Lesen Sie auch:

  • Rekursives Durchlaufen von Dateien und Ordnern mithilfe der Java File API
  • Sortieren benutzerdefinierter Typen in Java
  • Abfragen von Klasseninformationen zur Laufzeit mithilfe der Java Reflection API

Fragen:

  • Warum sollten wir Iterable- und Iterator-Schnittstellen in Java implementieren?
  • Wie sollten wir Iterable/Iterator-Schnittstellen implementieren?
  • Schauen wir uns ein einfaches Beispiel an.

    public class BasicStack<item> {
    
     public final int CAPACITY = 1000;
     private Item s();
     private int N;
    
     @SuppressWarnings("unchecked")
     public BasicStack() {
          s = (Item()) new Object(CAPACITY);
     }
    
     public Item pop() {
      Item item = s(--N);
      s(N) = null;
    
      return item;
     }
    
     public void push(Item item) {
      s(N++) = item;
     }
    }
    

    Der obige Code implementiert eine einfache Stack-Datenstruktur. Angenommen, wir möchten diese Datenstruktur dem Client zugänglich machen. Um über diese Datenstruktur zu iterieren, müssen Clients Iterator verwenden.

    public static void main(String() args) {
     BasicStack<integer> arrays = new BasicStack<integer>();
     arrays.push(4);
     arrays.push(8);
     arrays.push(31);
     arrays.push(7);
     arrays.pop();
     arrays.pop();
     Iterator<integer> i = arrays.iterator();
    
     while(i.hasNext()) {
      System.out.println(i.next());
     }
    }
    

    So weit so gut. Es ist nicht kompliziert, den obigen Client-Code über die Datenstruktur zu iterieren, außer dass Clients ihre eigenen Iteratoren codieren müssen. Da wir alle über Java-erweiterte For-Schleifen Bescheid wissen, wäre es nicht schöner, wenn die Clients erweiterte For-Schleifen für unsere Datenstrukturen verwenden könnten, anstatt ihre eigenen Iteratoren zu verwenden.

    Iterator<integer> i = arrays.iterator();
    
    while(i.hasNext()) {
          System.out.println(i.next());
    }
    

    Und

    for(Integer i: arrays)
         System.out.println(i);
    

    Derselbe Code wurde mit verbesserten For-Schleifen neu geschrieben, was eleganter aussieht. Aber erweiterte for-Schleifen können in den von uns implementierten Datenstrukturen nicht automatisch verwendet werden. Was machen wir dann? Hier kommt die Iterable-Schnittstelle ins Spiel. Nur wenn unsere Datenstruktur die Iterable-Schnittstelle implementiert, kann der Client mithilfe erweiterter for-Schleifen iterieren. Der Vorteil der Implementierung der Iterable-Schnittstelle besteht darin, dass der Client keine manuellen Iteratoren erstellen muss, um über unsere neuen Datenstrukturen zu iterieren, und die eleganten erweiterten For-Schleifen verwenden kann. Daher sollten wir die Java Iterable-Schnittstelle implementieren, um unseren Code eleganter zu gestalten.

    Iterierbare Schnittstelle

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

    Die iterierbare Schnittstelle ist ziemlich einfach. Wir müssen eine java.util.Iterator-Schnittstelle implementieren, die jede Sammlung durchlaufen kann.

    Iterator-Schnittstelle

    public interface Iterator<item> {
          boolean hasNext();
          Item next();
          void remove();
    }
    

    Die Iterator-Schnittstelle verfügt über drei Methoden: hashNext(), das prüft, ob es ein nächstes Element gibt, next(), das das nächste Element abruft, und dann remove(), das das zuletzt abgerufene Element aus der Sammlung entfernt. Im Allgemeinen empfehlen Java-Experten, die Methode „remove()“ nicht zu überschreiben und stattdessen eine Ausnahme zurückzugeben, wenn diese Methode aufgerufen wird. Nachdem wir uns die Grundlagen angesehen haben, schauen wir uns nun eine Implementierung an Iterierbar und Iterator Schnittstellen mit einem Beispiel.

    public class BasicStack<item> implements Iterable<item> {
    
     public static final int CAPACITY = 1000;
     private Item s();
     private int N;
    
     @SuppressWarnings("unchecked")
     public BasicStack() {
      s = (Item()) new Object(CAPACITY);
     }
    
     public Item pop() {
      Item item = s(--N);
      s(N) = null;
    
      return item;
     }
    
     public void push(Item item) {
      s(N++) = item;
     }
    
     public int size(){
      return N;
     }
    
     @Override
     public Iterator iterator() {
      return new ArrayIterator();
     }
    
     private class ArrayIterator implements Iterator<item> {
    
        private int i = N;
    
        @Override
        public boolean hasNext() {
      return i > 0;
        }
    
        @Override
        public Item next() {
      return s(--i);
        }
    
        @Override
        public void remove() {
           throw new UnsupportedOperationException();
    
        }
    
     }
    }
    

    Die Klasse BasicStack implementiert die Iterable-Schnittstelle und daher sollte die Methode iterator() überschrieben werden. Die Methode iterator() ruft eine neue Instanz der privaten Klasse ArrayIterator auf, die die Klasse java.util.Iterator implementiert und alle ihre Methoden überschreibt. Diese ArrayIterator-Klasse verfügt über die gesamte Logik zum Implementieren von Iteratoren.

    Wenn man sich den Code ansieht, prüft die Methode hasNext(), ob i>0 ist, also nur, ob es ein gültiges nächstes Element gibt. Die Methode next() gibt das aktuelle Element im Array zurück und dekrementiert dann den Zähler, um auf das nächste Element zu zeigen. Wie bereits vorgeschlagen, löst die Methode „remove()“ eine Ausnahme aus, falls der Benutzer versucht, diese Methode „remove()“ aufzurufen. Es ist Sache des Implementierers, zu entscheiden, ob er die Methode „remove()“ implementiert oder nicht. Wenn Clients also erweiterte For-Schleifen verwenden, ruft Java intern zuerst next() und dann next() auf, um die gesamte Sammlung zu durchlaufen.

    Wie man sieht, ist es ziemlich einfach, Iterable- und Iterator-Schnittstellen zu implementieren. Sobald dies implementiert ist, können die Clients unsere neuen Datenstrukturen mithilfe der erweiterten For-Schleifen iterieren, anstatt ihre eigenen Iteratoren schreiben zu müssen.

    Das ist alles über iterable und Iteratoren. Ich hoffe, die Lektüre hat Ihnen gefallen.

    Dieser Artikel wurde ursprünglich unter veröffentlicht Java-Tutorials – Lasst uns ins Meer springenhier mit Genehmigung des Autors und als Teil des JBC-Programms erneut veröffentlicht.

    Kommentar verfassen

    Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

    Nach oben scrollen