Lors de la création d'une classe wrapper pour un itérateur, il est souvent difficile d'implémenter hasNext. Si vous souhaitez simplement l'envelopper, vous pouvez le déléguer à un itérateur interne, mais si vous ne pouvez pas utiliser une telle stratégie pour plus de commodité.
Ce serait pratique si je pouvais jeter un coup d'œil à l'élément suivant ... Alors, faisons-le.
J'ai créé une classe, PeekableIterator, qui se comporte comme suit.
var src = java.util.List.of(3, 1, 4);
var peekIt = new PeekableIterator<>(src);
while(peekIt.hasNext()) {
System.out.printf("L'élément suivant est%ré.\n", peekIt.peek());
System.out.printf("Je vais le répéter.%ré.\n", peekIt.peek());
System.out.printf("Tu vois, vraiment%Était-ce d?\n", peekIt.next());
System.out.println();
}
System.out.println("La fin");
** Résultat d'exécution **
L'élément suivant est 3.
Je vais le répéter. C'est 3.
Vous voyez, c'était vraiment 3, non?
L'élément suivant est 1.
Je vais le répéter. C'est 1.
Vous voyez, c'était vraiment 1, non?
L'élément suivant est 4.
Je vais le répéter. C'est 4.
Vous voyez, c'était vraiment 4, non?
La fin
C'est une configuration simple avec seulement le constructeur et la méthode préférée peek () ajoutés. Lorsque hasNext () est false, peek () lève l'exception NoSuch ~. Cela retrace les spécifications de 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() { ... }
}
La configuration est la suivante. Considérant la possibilité que it.next () retourne null, nextElem et hasNext sont traités comme un ensemble.
private final Iterator<T> it; //Itérateur Omoto
private T nextElem; //Élément suivant
private boolean hasNext = false; //Les éléments suivants existent-ils?
Le constructeur jette un coup d'œil et contient les éléments suivants dans le champ.
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;
}
}
La méthode hasNext () n'est, après tout, qu'un getter. next () ne renvoie que nextElem, mais il a besoin d'un certain traitement pour voir l'élément suivant.
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;
}
L'implémentation de favorite peek () est également facile. Cependant, vous devez vérifier si nextElem n'est pas valide.
Java:PeekableIterator::peek
public T peek() throws NoSuchElementException {
if(!hasNext()) {
throw new NoSuchElementException();
}
return nextElem;
}
<détails> Lorsque l'itérateur est reçu par le constructeur, il n'est pas dupliqué.
Par conséquent, si l'appelant actionne directement l'itérateur, l'élément semblera ignoré. ** Résultat d'exécution ** Cependant, il semble impossible de rendre l'itérateur complètement indépendant. Ce serait bien s'il y avait un mécanisme pour donner à l'itérateur l'attribut "indisponible" ... Bien que ce soit comme spécifié. ** Résultat d'exécution ** Pour décider de l'interface de ce programme, j'ai fait référence à more_itertools.peekable de Python. Cependant, quand je le regarde à nouveau, il semble que Java fournit également une classe similaire.
Utilisons-le en faisant attention à la façon dont les points finaux sont traités. Apache Commons: Class PeekingIterator<E> Vous pouvez également obtenir une instance avec peekingIterator (), mais la différence avec le constructeur est inconnue. [^ 1]
Element () et peek () peuvent être utilisés correctement selon le but. Pratique pour la sobriété. ** Résultat d'exécution ** Guava: Interface PeekingIterator<E> Réception d'instances via Iterators.peekingIterator devenir.
Il n'y a pas de méthode element () ici, et le peek () de fin semble se terminer par une exception. C'est tout. [^ 1]: Je ne l'ai pas étudié si sérieusement, donc si je cherche sur Google de façon inattendue, il peut sortir bientôt.
Recommended Posts
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;
}
}
Problèmes d'utilisation
Problèmes causés par le fait de ne pas monopoliser l'itérateur
var it = java.util.List.of(3, 1, 4).iterator();
var peekIt = new itertools.PeekableIterator<>(it);
it.next();
while(peekIt.hasNext()) {
System.out.printf("L'élément suivant est%ré.\n", peekIt.peek());
System.out.printf("Je vais le répéter.%ré.\n", peekIt.peek());
System.out.printf("Tu vois, vraiment%Était-ce d?\n", peekIt.next());
System.out.println();
}
System.out.println("La fin");
L'élément suivant est 3.
Je vais le répéter. C'est 3.
Vous voyez, c'était vraiment 3, non?
L'élément suivant est 4.
Je vais le répéter. C'est 4.
Vous voyez, c'était vraiment 4, non?
La fin
Un problème où une exception se produit lorsque peek () est effectué à un point de terminaison
var src = java.util.List.of(3, 1);
var peekIt = new PeekableIterator<>(src);
while(peekIt.hasNext()) {
System.out.printf("L'élément actuel est%ré.\n", peekIt.next());
System.out.printf("L'élément suivant est%ré. impatient de.\n", peekIt.peek());
System.out.println();
}
System.out.println("La fin");
L'élément actuel est 3.
L'élément suivant est 1. impatient de.
L'élément actuel est 1.
Exception in thread "main" java.util.NoSuchElementException
at ...
Bibliothèque existante
var src = java.util.List.of(3, 1);
var peekIt = new PeekingIterator<>(src.iterator());
while(peekIt.hasNext()) {
System.out.printf("L'élément actuel est%ré.\n", peekIt.next());
System.out.printf("L'élément suivant est%ré. impatient de.(peek)\n", peekIt.peek());
System.out.printf("L'élément suivant est%ré. impatient de.(element)\n", peekIt.element());
System.out.println();
}
System.out.println("La fin");
L'élément actuel est 3.
L'élément suivant est 1. impatient de.(peek)
L'élément suivant est 1. impatient de.(element)
L'élément actuel est 1.
L'élément suivant est nul. impatient de.(peek)
Exception in thread "main" java.util.NoSuchElementException
at ...
var src = java.util.List.of(3, 1);
var peekIt = Iterators.peekingIterator(src.iterator());
while(peekIt.hasNext()) {
System.out.printf("L'élément actuel est%ré.\n", peekIt.next());
System.out.printf("L'élément suivant est%ré. impatient de.\n", peekIt.peek());
System.out.println();
}
System.out.println("La fin");
L'élément actuel est 3.
L'élément suivant est 1. impatient de.
L'élément actuel est 1.
Exception in thread "main" java.util.NoSuchElementException
at ...
Postscript