JavaRush /Java-Blog /Random-DE /Iteratormuster

Iteratormuster

Veröffentlicht in der Gruppe Random-DE
Heute werden wir darüber sprechen, was Iterator in Java ist und warum er benötigt wird.
Iteratormuster – 1
Wie Sie wahrscheinlich bereits wissen, verfügt Java über eine wunderbare Collection-Schnittstelle, die die Iterator-Schnittstelle implementiert. Lassen Sie mich gleich einen Vorbehalt machen: Die Iterator-Schnittstelle sollte nicht mit dem Iterator-Muster in Java verwechselt werden! Schauen wir uns zur Verdeutlichung zunächst die Benutzeroberfläche an.
Wörtlich kann „Iterator“ mit „brutale Gewalt “ übersetzt werden . Das heißt, es handelt sich um eine bestimmte Entität, die alle Elemente in der Sammlung durchlaufen kann. Darüber hinaus können Sie dies tun, ohne sich mit der internen Struktur und Anordnung von Sammlungen befassen zu müssen.
Stellen wir uns für eine Sekunde vor, dass es in Java keinen Iterator gibt. In diesem Fall muss jeder einzelne in die Tiefen der Sammlungen eintauchen und wirklich verstehen, was sich ArrayListvon LinkedListihnen HashSetunterscheidet TreeSet.

Methoden, die der Iterator implementieren muss

boolean hasNext()— Wenn im iterierbaren Objekt (derzeit eine Sammlung) noch Werte vorhanden sind, gibt die Methode zurück true, wenn keine Werte mehr vorhanden sind false. E next()– gibt das nächste Element der Sammlung (Objekt) zurück. Wenn keine weiteren Elemente vorhanden sind (es gab keine check hasNext()und wir haben aufgerufen, next()als wir das Ende der Sammlung erreicht hatten), löst die Methode aus NoSuchElementException. void remove()- Entfernt das Element, das zuletzt von erhalten wurde next(). Die Methode kann Folgendes auslösen:
  • UnsupportedOperationException, wenn dieser Iterator die Methode nicht unterstützt remove()(z. B. bei schreibgeschützten Sammlungen)
  • IllegalStateException, wenn die Methode next()noch nicht aufgerufen wurde oder remove()bereits seit dem letzten Aufruf aufgerufen wurde next().
Daher ist der Iterator für List die häufigste Implementierung. Der Iterator geht vom Anfang der Sammlung bis zu ihrem Ende: Er prüft, ob das nächste Element vorhanden ist, und gibt es zurück, wenn eines vorhanden ist. Auf Basis dieses einfachen Algorithmus wird ein Zyklus aufgebaut for-each. Seine Erweiterung ist ListIterator. Schauen wir uns weitere Java-Listeniteratormethoden an. Sie kennen sie höchstwahrscheinlich:
  • void add(E e)– fügt ein Element Eein in ;List
  • boolean hasPrevious()– wird zurückgegeben true, wenn Listwährend der Rückwärtssuche Elemente vorhanden sind;
  • int nextIndex()– gibt den Index des nächsten Elements zurück;
  • E previous()– gibt das vorherige Blattelement zurück;
  • int previousIndex()– gibt den Index des vorherigen Elements zurück;
  • void set(E e)- ersetzt das beim letzten Aufruf zurückgegebene Element next()oder previous()durch das Element e.
Schauen wir uns ein kleines Beispiel an. Erstellen wir eine Listmit den Begrüßungszeilen für die Schüler:
List<String> list = new ArrayList<>();
list.add("Hallo");
list.add("Обучающимся");
list.add("На");
list.add("JavaRush");
Jetzt besorgen wir uns einen Iterator dafür und geben alle enthaltenen Zeilen auf der Konsole aus:
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}
Jetzt wird es einen „Engpass“ geben: Java Collections erweitern, wie Sie wahrscheinlich wissen (und wenn Sie es nicht wissen, finden Sie es heraus), die Schnittstelle Iterable, aber das bedeutet nicht nur List, dass Setsie QueueIteratoren unterstützen. For java Map iteratorwird ebenfalls unterstützt, muss aber aufgerufen werden Map.entrySet():
Map<String, Integer> map = new HashMap<>();
Iterator mapIterator = map.entrySet().iterator();
next() Dann gibt die Methode ein Objekt zurück Entry, das ein „Schlüssel“-„Wert“-Paar enthält. Dann ist alles beim Alten mit List:
while (mapIterator.hasNext()) {
    Map.Entry<String, Integer> entry = mapIterator.next();
    System.out.println("Key: " + entry.getKey());
    System.out.println("Value: " + entry.getValue());
}
Du denkst: „Hör auf. Wir sprechen über die Schnittstelle und der Titel des Artikels lautet „Muster“. Das heißt, das Iteratormuster ist die Iteratorschnittstelle? Oder ist die Schnittstelle ein Muster? Wenn dieses Wort zum ersten Mal auftaucht, gebe ich Ihnen einen Hinweis: Ein Muster ist ein Entwurfsmuster, ein bestimmtes Verhalten, an das sich eine Klasse oder viele miteinander verbundene Klassen halten müssen. Ein Iterator in Java kann für jedes Objekt implementiert werden, dessen interne Struktur eine Iteration beinhaltet, und Sie können die Signatur der besprochenen Methoden ändern. Bei der Implementierung eines Musters kommt es vor allem auf die Logik an, die die Klasse einhalten muss. Die Iterator-SchnittstelleList, Set, Queue, Map ist eine private Implementierung des gleichnamigen Musters, die nach Ermessen des Programmierers sowohl auf vorgefertigte Strukturen ( ) als auch auf andere angewendet wird . Durch die Erweiterung der Iterator-Schnittstelle implementieren Sie ein Muster, müssen die Schnittstelle jedoch nicht erweitern, um das Muster zu implementieren. Eine einfache Analogie: Alle Fische schwimmen, aber nicht alles, was schwimmt, ist ein Fisch. Als Beispiel habe ich beschlossen, ... das Wort zu nehmen. Genauer gesagt, ein Substantiv. Es besteht aus Teilen: Präfix, Wurzel, Suffix und Endung. Für Wortteile erstellen wir eine Schnittstelle WordPartund Klassen, die diese erweitern: Prefix, Root, Suffix и Ending:
interface WordPart {
    String getWordPart();
}

static class Root implements WordPart {

    private String part;

    public Root(String part) {
        this.part = part;
    }

    @Override
    public String getWordPart() {
        return part;
    }
}

static class Prefix implements WordPart {

    private String part;

    public Prefix(String part) {
        this.part = part;
    }

    @Override
    public String getWordPart() {
        return part;
    }
}

static class Suffix implements WordPart {

    private String part;

    public Suffix(String part) {
        this.part = part;
    }

    @Override
    public String getWordPart() {
        return part;
    }
}

static class Ending implements WordPart {

    private String part;

    public Ending(String part) {
        this.part = part;
    }

    @Override
    public String getWordPart() {
        return part;
    }
}
Dann Wordenthält die Klasse (das Wort) Teile, und zusätzlich zu ihnen fügen wir eine Ganzzahl hinzu, die die Anzahl der Teile im Wort widerspiegelt:
public class Word {

    private Root root;
    private Prefix prefix;
    private Suffix suffix;
    private Ending ending;
    private int partCount;

    public Word(Root root, Prefix prefix, Suffix suffix, Ending ending) {
        this.root = root;
        this.prefix = prefix;
        this.suffix = suffix;
        this.ending = ending;
        this.partCount = 4;
    }

    public Word(Root root, Prefix prefix, Suffix suffix) {
        this.root = root;
        this.prefix = prefix;
        this.suffix = suffix;
        this.partCount = 3;

    }

    public Word(Root root, Prefix prefix) {
        this.root = root;
        this.prefix = prefix;
        this.partCount = 2;
    }

    public Word(Root root) {
        this.root = root;
        this.partCount = 1;
    }

    public Root getRoot() {
        return root;
    }

    public Prefix getPrefix() {
        return prefix;
    }

    public Suffix getSuffix() {
        return suffix;
    }

    public Ending getEnding() {
        return ending;
    }

    public int getPartCount() {
        return partCount;
    }

    public boolean hasRoot() {
        return this.root != null;
    }

    public boolean hasPrefix() {
        return this.prefix != null;
    }

    public boolean hasSuffix() {
        return this.suffix != null;
    }

    public boolean hasEnding() {
        return this.ending != null;
    }
Okay, wir haben vier überladene Konstruktoren (der Einfachheit halber nehmen wir an, wir können nur ein Suffix haben). Ein Substantiv kann nicht aus einem Präfix bestehen, daher legen wir für einen Konstruktor mit einem Parameter die Wurzel fest. Schreiben wir nun eine Implementierung des Iteratormusters: WordIterator, die zwei Methoden überschreibt: hasNext()und next():
public class WordIterator implements Iterator<Word.WordPart> {

    private Word word;
    private int wordPartsCount;

    public WordIterator(Word word) {
        this.word = word;
        this.wordPartsCount = word.getPartCount();
    }

    @Override
    public boolean hasNext() {
        if (wordPartsCount == 4) {
            return word.hasPrefix() || word.hasRoot() || word.hasSuffix() || word.hasEnding();
        } else if (wordPartsCount == 3) {
            return word.hasPrefix() || word.hasRoot() || word.hasSuffix();
        } else if (wordPartsCount == 2) {
            return word.hasPrefix() || word.hasRoot();
        } else if (wordPartsCount == 1) {
            return word.hasRoot();
        }
        return false;
    }

    @Override
    public Word.WordPart next() throws NoSuchElementException {
        if (wordPartsCount <= 0) {
            throw new NoSuchElementException("No more elements in this word!");
        }

        try {
            if (wordPartsCount == 4) {
                return word.getEnding();
            }
            if (wordPartsCount == 3) {
                return word.getSuffix();
            }
            if (wordPartsCount == 2) {
                return word.getPrefix();
            }
            return word.getRoot();
        } finally {
            wordPartsCount--;
        }
    }
}
Jetzt muss nur noch der Klasse der Iterator zugewiesen werden Word:
public class Word implements Iterable<Word.WordPart> {@Override
	public Iterator<WordPart>iterator() {
    		return new WordIterator(this);
	}}
Lassen Sie uns nun eine morphemische Analyse des Wortes „Rush“ durchführen:
public class Main {
    public static void main(String[] args) {
        Word.Root root = new Word.Root("беж");
        Word.Prefix prefix = new Word.Prefix("пере");
        Word.Suffix suffix = new Word.Suffix("к");
        Word.Ending ending = new Word.Ending("a");

        Word word = new Word(root, prefix, suffix, ending);

        Iterator wordIterator = word.iterator();
        while (wordIterator.hasNext()) {
            Word.WordPart part = (Word.WordPart) wordIterator.next();
            System.out.println(part.getClass() + ": " + part.getWordPart());
        }
    }
}
Bitte beachten Sie, dass ich bei meiner Implementierung des Iteratormusters die folgende Ausgabereihenfolge gewählt habe:
  1. Ende
  2. Suffix
  3. Konsole
  4. Wurzel
Beim Entwurf Ihres eigenen Iterators können Sie den Iterationsalgorithmus nach Ihren Wünschen festlegen. Viel Erfolg im Studium!
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION