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.
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
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() { ... }
}
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?
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;
}
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;
}
}
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 ...
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 ...
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 ...
Das ist es.
[^ 1]: Ich habe es nicht so ernsthaft untersucht. Wenn ich es also unerwartet google, kann es bald herauskommen.
Recommended Posts