[JAVA] Essayez de créer un itérateur qui puisse être vu

Préface

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.

Sujet principal

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

la mise en oeuvre

Configuration de la méthode

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() { ... }
}

Composition du champ

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?

Implémentation de la méthode

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>

** Code global ** </ summary>

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

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é.

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");

** 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 4.
Je vais le répéter. C'est 4.
Vous voyez, c'était vraiment 4, non?

La fin

Cependant, il semble impossible de rendre l'itérateur complètement indépendant.

  • L'itérateur est, pour ainsi dire, un "état", et cela dépend du fournisseur s'il peut être dupliqué tel quel.
  • Vous pouvez créer n'importe quel nombre d'itérateurs en lisant tous les éléments, mais le mérite de retarder l'acquisition des éléments disparaît.
  • En premier lieu, lorsque tous les éléments sont lus, l'itérateur d'origine se fane. ―― Qu'en est-il d'un itérateur qui renvoie des éléments indéfiniment en premier lieu?

Ce serait bien s'il y avait un mécanisme pour donner à l'itérateur l'attribut "indisponible" ...

Un problème où une exception se produit lorsque peek () est effectué à un point de terminaison

Bien que ce soit comme spécifié.

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");

** Résultat d'exécution **

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

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é.

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");

** Résultat d'exécution **

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 ...

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.

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

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

Essayez de créer un itérateur qui puisse être vu
Essayez de faire un simple rappel
Comment créer un conteneur Java
[Débutant] Essayez de créer un jeu RPG simple avec Java ①
Comment créer un écran de démarrage
Comment faire un projet Maven
Essayez de créer une application client serveur
CompletableFuture Getting Started 2 (Essayez de faire CompletableFuture)
Comment créer un tableau Java
Essayez de créer une tuile de dessin en trois dimensions CS à partir de la tuile Institut géographique
Comment créer un robot Discord (Java)
Faire une marge à gauche du TextField
Essayez de créer un babillard en Java
Comportement incrémenté Essayez de créer un problème Java TypeScript 3-4
Je voulais que (a == 1 && a == 2 && a == 3) vrai en Java
Opération de chaîne de caractères Essayez de changer le problème Java en TypeScript 9-3
Comment créer un JRE léger pour la distribution
Essayez de faire un rapport chronologique du temps d'exécution d'une méthode à l'aide de l'API JFR
[Introduction] Créer une application Ruby on Rails
Essayez de libérer la gemme
Initialisation de for Essayez de changer le problème Java en TypeScript 5-4
Comment faire fonctionner JavaScript sur une page spécifique
Essayez de faire un programme d'addition en plusieurs langues
J'ai essayé de créer une fonction de connexion avec Java
Comment faire un pot ombré
Créer un utilitaire de réflexion ②
Créer un utilitaire de réflexion ③
Essayez de résoudre un problème FizzBuzz restreint en Java
Comment faire un cache sans trop réfléchir
Créer un utilitaire de réflexion ①
Comment faire un MOD pour Slay the Spire
Essayez de créer un environnement de développement Java à l'aide de Docker
Essayez d'envoyer une notification.
[Introduction au développement d'applications Android] Faisons un compteur
Remarques à vérifier lorsque vous essayez d'utiliser Lombok
Je souhaite créer un modèle spécifique d'ActiveRecord ReadOnly
Je veux faire une liste avec kotlin et java!
Je voulais juste créer une propriété réactive en Java
Je veux créer une fonction avec kotlin et java!
Apprendre Ruby avec AtCoder 13 Comment créer un tableau à deux dimensions
J'ai créé un client RESAS-API en Java
Essayez Spring Boot de 0 à 100.
Comment laisser un commentaire
Pour effectuer des requêtes lourdes de manière asynchrone
Passez des variables à Scope.
[Java] Rendez-le constant
Essayez d'implémenter une session WebFlux
Pour écrire un programme orienté utilisateur (1)
[Rails] Faites une liste de miettes de pain
Introduction aux modèles de conception (Iterator)
Essayez d'implémenter un filtre WebFlux
[Rails] Comment faire des graines
Comment insérer une vidéo
Faire un diamant en utilisant Java
Comment créer une méthode
Essayez d'imiter l'idée d'un tableau à deux dimensions avec un tableau à une dimension
Comment créer un hinadan pour un projet Spring Boot à l'aide de SPRING INITIALIZR
Comment créer un fichier jar sans dépendances dans Maven
[Unity] J'ai essayé de créer un plug-in natif UniNWPathMonitor en utilisant NWPathMonitor