[JAVA] Versuchen Sie, einen Iterator zu erstellen, der einen Blick darauf werfen kann

Vorwort

Beim Erstellen einer Wrapper-Klasse für einen Iterator ist es oft schwierig, hasNext zu implementieren. Wenn Sie es nur umbrechen möchten, können Sie es an einen internen Iterator delegieren. Wenn Sie eine solche Strategie jedoch nicht verwenden können, können Sie dies bequemer machen.

Es wäre praktisch, wenn ich einen Blick auf das nächste Element werfen könnte ... Also, machen wir es.

Hauptthema

Ich habe eine Klasse namens PeekableIterator erstellt, die sich wie folgt verhält.

var src = java.util.List.of(3, 1, 4);

var peekIt = new PeekableIterator<>(src);
while(peekIt.hasNext()) {
    System.out.printf("Das nächste Element ist%d.\n", peekIt.peek());
    System.out.printf("Ich werde es noch einmal sagen.%d.\n", peekIt.peek());
    System.out.printf("Sie sehen wirklich%War es d?\n", peekIt.next());
    System.out.println();
}
System.out.println("Das Ende");

** Ausführungsergebnis **

Das nächste Element ist 3.
Ich werde es noch einmal sagen. Es ist 3.
Sie sehen, es war wirklich 3, richtig?

Das nächste Element ist 1.
Ich werde es noch einmal sagen. Es ist 1.
Sie sehen, es war wirklich 1, richtig?

Das nächste Element ist 4.
Ich werde es noch einmal sagen. Es ist 4.
Sie sehen, es war wirklich 4, richtig?

Das Ende

Implementierung

Methodenkonfiguration

Es ist eine einfache Konfiguration, bei der nur der Konstruktor und die bevorzugte Methode peek () hinzugefügt werden. Wenn hasNext () false ist, löst peek () die Ausnahme NoSuch ~ aus. Dies verfolgt die Spezifikationen von Iterator # next ().

PeekableIterator.java


import java.util.Iterator;
import java.util.NoSuchElementException;

public class PeekableIterator<T> implements Iterator<T> {
    public PeekableIterator(Iterable<T> iterable) { ... }
    public PeekableIterator(Iterator<T> it) { ... }
    
    public T peek() throws NoSuchElementException { ... }

    @Override
    public T next() throws NoSuchElementException { ... }
    @Override
    public boolean hasNext() { ... }
}

Feldzusammensetzung

Die Konfiguration ist wie folgt. In Anbetracht der Möglichkeit, dass it.next () null zurückgibt, werden nextElem und hasNext als Menge behandelt.

private final Iterator<T> it;      //Omoto Iterator
private T nextElem;                //Nächstes Element
private boolean hasNext = false;   //Gibt es folgende Elemente?

Methodenimplementierung

Der Konstruktor wirft einen Blick darauf und enthält die folgenden Elemente im Feld.

PeekableIterator#new


public PeekableIterator(Iterable<T> iterable) {
    this(iterable.iterator());
}
public PeekableIterator(Iterator<T> it) {
    this.it = it;

    if(it.hasNext()) {
        nextElem = it.next();
        hasNext = true;
    }
}

Die Methode hasNext () ist schließlich nur ein Getter. next () gibt nur nextElem zurück, benötigt jedoch einige Verarbeitung, um in das nächste Element zu blicken.

PeekableIterator#hasNext,#next


@Override
public boolean hasNext() {
    return hasNext;
}

@Override
public T next() throws NoSuchElementException {
    if(!hasNext()) {
        throw new NoSuchElementException();
    }

    final T ret = nextElem;
    if(it.hasNext()) { nextElem = it.next(); }
    else { hasNext = false; }

    return ret;
}

Die Implementierung von Favorite Peek () ist ebenfalls einfach. Sie müssen jedoch überprüfen, ob nextElem ungültig ist.

Java:PeekableIterator::peek


public T peek() throws NoSuchElementException {
    if(!hasNext()) {
        throw new NoSuchElementException();
    }
    return nextElem; 
}
** Gesamtcode **

Peekable.java


import java.util.Iterator;
import java.util.NoSuchElementException;

public class PeekableIterator<T> implements Iterator<T> {
    //
    private final Iterator<T> it;
    private T nextElem;
    private boolean hasNext = false;

    public PeekableIterator(Iterable<T> iterable) {
        this(iterable.iterator());
    }
    public PeekableIterator(Iterator<T> it) {
        this.it = it;

        if (it.hasNext()) {
            nextElem = it.next();
            hasNext = true;
        }
    }

    //
    public T peek() throws NoSuchElementException {
        if (!hasNext()) {
            throw new NoSuchElementException();
        }
        return nextElem;
    }

    //
    @Override
    public boolean hasNext() {
        return hasNext;
    }
    @Override
    public T next() throws NoSuchElementException {
        if (!hasNext()) {
            throw new NoSuchElementException();
        }

        final T ret = nextElem;
        if (it.hasNext()) {
            nextElem = it.next();
        } else {
            hasNext = false;
        }
        return ret;
    }
}

Nutzungsprobleme

Probleme, die dadurch verursacht werden, dass der Iterator nicht monopolisiert wird

Wenn der Iterator vom Konstruktor empfangen wird, wird er nicht dupliziert. Wenn der Aufrufer den Iterator direkt bedient, wird das Element daher anscheinend übersprungen.

var it = java.util.List.of(3, 1, 4).iterator();
var peekIt = new itertools.PeekableIterator<>(it);

it.next();

while(peekIt.hasNext()) {
    System.out.printf("Das nächste Element ist%d.\n", peekIt.peek());
    System.out.printf("Ich werde es noch einmal sagen.%d.\n", peekIt.peek());
    System.out.printf("Sie sehen wirklich%War es d?\n", peekIt.next());
    System.out.println();
}
System.out.println("Das Ende");

** Ausführungsergebnis **

Das nächste Element ist 3.
Ich werde es noch einmal sagen. Es ist 3.
Sie sehen, es war wirklich 3, richtig?

Das nächste Element ist 4.
Ich werde es noch einmal sagen. Es ist 4.
Sie sehen, es war wirklich 4, richtig?

Das Ende

Es scheint jedoch unmöglich, den Iterator vollständig unabhängig zu machen.

Es wäre schön, wenn es einen Mechanismus gäbe, der dem Iterator das Attribut "nicht verfügbar" gibt ...

Ein Problem, bei dem eine Ausnahme auftritt, wenn peek () an einem Endpunkt ausgeführt wird

Obwohl es wie angegeben ist.

var src = java.util.List.of(3, 1);
var peekIt = new PeekableIterator<>(src);

while(peekIt.hasNext()) {
    System.out.printf("Das aktuelle Element ist%d.\n", peekIt.next());
    System.out.printf("Das nächste Element ist%d. Ich freue mich darauf.\n", peekIt.peek());
    System.out.println();
}
System.out.println("Das Ende");

** Ausführungsergebnis **

Das aktuelle Element ist 3.
Das nächste Element ist 1. Ich freue mich darauf.

Das aktuelle Element ist 1.
Exception in thread "main" java.util.NoSuchElementException
        at ...

Bestehende Bibliothek

Bei der Entscheidung über die Schnittstelle dieses Programms habe ich auf more_itertools.peekable von Python verwiesen.

Wenn ich es jedoch noch einmal nachschaue, scheint es, dass Java auch eine ähnliche Klasse bietet. Verwenden wir es tatsächlich, während wir darauf achten, wie die Endpunkte verarbeitet werden.

Apache Commons: Class PeekingIterator<E>

Sie können auch eine Instanz mit peekingIterator () abrufen, der Unterschied zum Konstruktor ist jedoch unbekannt. [^ 1] Element () und peek () können je nach Verwendungszweck ordnungsgemäß verwendet werden. Praktisch für Nüchternheit.

var src = java.util.List.of(3, 1);
var peekIt = new PeekingIterator<>(src.iterator());

while(peekIt.hasNext()) {
    System.out.printf("Das aktuelle Element ist%d.\n", peekIt.next());
    System.out.printf("Das nächste Element ist%d. Ich freue mich darauf.(peek)\n", peekIt.peek());
    System.out.printf("Das nächste Element ist%d. Ich freue mich darauf.(element)\n", peekIt.element());
    System.out.println();
}
System.out.println("Das Ende");

** Ausführungsergebnis **

Das aktuelle Element ist 3.
Das nächste Element ist 1. Ich freue mich darauf.(peek)
Das nächste Element ist 1. Ich freue mich darauf.(element)

Das aktuelle Element ist 1.
Das nächste Element ist null. Ich freue mich darauf.(peek)
Exception in thread "main" java.util.NoSuchElementException
        at ...

Guava: Interface PeekingIterator<E>

Empfangen von Instanzen über Iterators.peekingIterator werden. Hier gibt es keine element () -Methode, und das Beenden von peek () scheint mit einer Ausnahme zu enden.

var src = java.util.List.of(3, 1);
var peekIt = Iterators.peekingIterator(src.iterator());
while(peekIt.hasNext()) {
    System.out.printf("Das aktuelle Element ist%d.\n", peekIt.next());
    System.out.printf("Das nächste Element ist%d. Ich freue mich darauf.\n", peekIt.peek());
    System.out.println();
}
System.out.println("Das Ende");
Das aktuelle Element ist 3.
Das nächste Element ist 1. Ich freue mich darauf.

Das aktuelle Element ist 1.
Exception in thread "main" java.util.NoSuchElementException
        at ...

Nachtrag

Das ist es.

[^ 1]: Ich habe es nicht so ernsthaft untersucht. Wenn ich es also unerwartet google, kann es bald herauskommen.

Recommended Posts

Versuchen Sie, einen Iterator zu erstellen, der einen Blick darauf werfen kann
Versuchen Sie, einen einfachen Rückruf zu tätigen
So erstellen Sie einen Java-Container
[Anfänger] Versuchen Sie, mit Java ein einfaches RPG-Spiel zu erstellen ①
So erstellen Sie einen Begrüßungsbildschirm
Wie erstelle ich ein Maven-Projekt?
Versuchen Sie, eine Server-Client-App zu erstellen
CompletableFuture Erste Schritte 2 (Versuchen Sie, CompletableFuture zu erstellen)
So erstellen Sie ein Java-Array
Versuchen Sie, aus der Kachel des Geographical Institute eine dreidimensionale CS-Zeichnungskachel zu erstellen
Wie erstelle ich einen Discord Bot (Java)
Machen Sie einen Rand links vom TextField
Versuchen Sie, ein Bulletin Board in Java zu erstellen
Inkrementierungsverhalten Versuchen Sie, Java zum Problem TypeScript 3-4 zu machen
Ich wollte (a == 1 && a == 2 && a == 3) in Java wahr machen
Zeichenfolgenoperation Versuchen Sie, das Java-Problem in TypeScript 9-3 zu ändern
So erstellen Sie eine leichte JRE für den Vertrieb
Versuchen Sie, mithilfe der JFR-API einen Zeitleistenbericht über die Ausführungszeit einer Methode zu erstellen
[Einführung] Erstellen Sie eine Ruby on Rails-Anwendung
Versuche Edelstein freizugeben
Initialisierung von for Versuchen Sie, das Java-Problem in TypeScript 5-4 zu ändern
So funktioniert JavaScript auf einer bestimmten Seite
Versuchen Sie, ein Zusatzprogramm in mehreren Sprachen zu erstellen
Ich habe versucht, eine Anmeldefunktion mit Java zu erstellen
Wie man ein schattiertes Glas macht
Erstellen Sie ein Reflexionsprogramm ②
Erstellen Sie ein Reflexionsprogramm ③
Versuchen Sie, ein eingeschränktes FizzBuzz-Problem in Java zu lösen
Wie man einen Cache erstellt, ohne zu viel nachzudenken
Erstellen Sie ein Reflexionsprogramm ①
Wie erstelle ich einen MOD für Slay the Spire?
Versuchen Sie, mit Docker eine Java-Entwicklungsumgebung zu erstellen
Versuchen Sie, eine Benachrichtigung zu senden.
[Einführung in die Android App-Entwicklung] Machen wir einen Zähler
Hinweise zur Überprüfung bei der Verwendung von Lombok
Ich möchte ein bestimmtes Modell von ActiveRecord ReadOnly erstellen
Ich möchte eine Liste mit Kotlin und Java erstellen!
Ich wollte nur eine reaktive Eigenschaft in Java erstellen
Ich möchte eine Funktion mit Kotlin und Java erstellen!
Ruby mit AtCoder lernen 13 So erstellen Sie ein zweidimensionales Array
Ich habe einen RESAS-API-Client in Java erstellt
Versuchen Sie Spring Boot von 0 bis 100.
Wie hinterlasse ich einen Kommentar?
Schwere Abfragen asynchron durchführen
Übergeben Sie Variablen an Scope.
[Java] Mach es konstant
Versuchen Sie, eine WebFlux-Sitzung zu implementieren
So schreiben Sie ein benutzerorientiertes Programm (1)
[Schienen] Machen Sie eine Brotkrumenliste
Einführung in Entwurfsmuster (Iterator)
Versuchen Sie, einen WebFlux-Filter zu implementieren
[Schienen] Wie man Samen macht
So fügen Sie ein Video ein
Machen Sie einen Diamanten mit Java
So erstellen Sie eine Methode
Versuchen Sie, die Idee eines zweidimensionalen Arrays mit einem eindimensionalen Array nachzuahmen
So erstellen Sie mit SPRING INITIALIZR einen Hinadan für ein Spring Boot-Projekt
So erstellen Sie eine JAR-Datei ohne Abhängigkeiten in Maven
[Unity] Ich habe mit NWPathMonitor ein natives Plug-In UniNWPathMonitor erstellt