web-dev-qa-db-fra.com

Pouvons-nous écrire notre propre itérateur en Java?

Si j'ai une liste contenant [alice, bob, abigail, charlie] et que je veux écrire un itérateur de manière à itérer sur les éléments commençant par 'a', puis-je écrire le mien? Comment puis je faire ça ?

87
phoenix

Sûr. Un itérateur est simplement une implémentation de l'interface Java.util.Iterator . Si vous utilisez un objet itérable existant (par exemple, un LinkedList) de _Java.util_, vous devez le sous-classer et remplacer sa fonction iterator de sorte que vous retourniez le vôtre, ou fournissez un moyen d'envelopper un itérateur standard dans votre instance spéciale Iterator (qui a l'avantage d'être utilisée plus largement), etc.

40
T.J. Crowder

La meilleure option réutilisable consiste à implémenter l'interface Iterable et à remplacer la méthode iterator ().

Voici un exemple de classe de type ArrayList implémentant l'interface, dans laquelle vous substituez la méthode Iterator ().

import Java.util.Iterator;

public class SOList<Type> implements Iterable<Type> {

    private Type[] arrayList;
    private int currentSize;

    public SOList(Type[] newArray) {
        this.arrayList = newArray;
        this.currentSize = arrayList.length;
    }

    @Override
    public Iterator<Type> iterator() {
        Iterator<Type> it = new Iterator<Type>() {

            private int currentIndex = 0;

            @Override
            public boolean hasNext() {
                return currentIndex < currentSize && arrayList[currentIndex] != null;
            }

            @Override
            public Type next() {
                return arrayList[currentIndex++];
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
        return it;
    }
}

Cette classe implémente l'interface Iterable en utilisant Generics . En considérant que vous avez des éléments dans le tableau, vous pourrez obtenir une instance d'un Iterator, qui est l'instance nécessaire utilisée par la boucle "foreach", par exemple.

Vous pouvez simplement créer une instance anonyme de l'itérateur sans créer l'extension Iterator et tirer parti de la valeur de currentSize pour vérifier jusqu'à l'endroit où vous pouvez naviguer dans le tableau (supposons que vous ayez créé un tableau d'une capacité de 10, mais vous n'avez que 2 éléments à 0 et 1). L'instance aura son compteur propriétaire où elle se trouve et tout ce que vous avez à faire est de jouer avec hasNext (), qui vérifie si la valeur actuelle n'est pas nulle, et le next (), qui renverra l'instance de votre currentIndex. Vous trouverez ci-dessous un exemple d'utilisation de cette API ...

public static void main(String[] args) {
    // create an array of type Integer
    Integer[] numbers = new Integer[]{1, 2, 3, 4, 5};

    // create your list and hold the values.
    SOList<Integer> stackOverflowList = new SOList<Integer>(numbers);

    // Since our class SOList is an instance of Iterable, then we can use it on a foreach loop
    for(Integer num : stackOverflowList) {
        System.out.print(num);
    }

    // creating an array of Strings
    String[] languages = new String[]{"C", "C++", "Java", "Python", "Scala"};

    // create your list and hold the values using the same list implementation.
    SOList<String> languagesList = new SOList<String>(languages);

    System.out.println("");
    // Since our class SOList is an instance of Iterable, then we can use it on a foreach loop
    for(String lang : languagesList) {
        System.out.println(lang);
    }
}
// will print "12345
//C
//C++
//Java
//Python
//Scala

Si vous le souhaitez, vous pouvez également effectuer une itération à l'aide de l'instance Iterator:

// navigating the iterator
while (allNumbers.hasNext()) {
    Integer value = allNumbers.next();
    if (allNumbers.hasNext()) {
        System.out.print(value + ", ");
    } else {
        System.out.print(value);
    }
} 
// will print 1, 2, 3, 4, 5

La documentation de foreach se trouve à l'adresse http://download.Oracle.com/javase/1,5.0/docs/guide/language/foreach.html . Vous pouvez jeter un coup d'œil à une implémentation plus complète de ma pratique personnelle google code .

Maintenant, pour obtenir les effets de ce dont vous avez besoin, il est nécessaire d'insérer un concept de filtre dans l'Iterator ... Puisque l'itérateur dépend des valeurs suivantes, il serait difficile de renvoyer true à hasNext (), puis filtrer l'implémentation next () avec une valeur qui ne commence pas par un caractère "a" par exemple. Je pense que vous devez jouer avec un Interator secondaire basé sur une liste filtrée avec les valeurs avec le filtre donné.

178

Bon exemple pour Iterable pour calculer factoriel

FactorialIterable fi = new FactorialIterable(10);
Iterator<Integer> iterator = fi.iterator();
while (iterator.hasNext()){
     System.out.println(iterator.next());
}

peu de code pour Java 1.8

new FactorialIterable(5).forEach(System.out::println);

classe Iterable personnalisée

public class FactorialIterable implements Iterable<Integer> {

    private final FactorialIteartor factorialIteartor;

    public FactorialIterable(Integer value) {
        factorialIteartor = new FactorialIteartor(value);
    }

    @Override
    public Iterator<Integer> iterator() {
        return factorialIteartor;
    }

    @Override
    public void forEach(Consumer<? super Integer> action) {
        Objects.requireNonNull(action);
        Integer last = 0;
        for (Integer t : this) {
            last = t;
        }
        action.accept(last);
    }

}

classe d'itérateur personnalisée

public class FactorialIteartor implements Iterator<Integer> {

    private final Integer mNumber;
    private Integer mPosition;
    private Integer mFactorial;


    public FactorialIteartor(Integer number) {
        this.mNumber = number;
        this.mPosition = 1;
        this.mFactorial = 1;
    }

    @Override
    public boolean hasNext() {
        return mPosition <= mNumber;
    }

    @Override
    public Integer next() {
        if (!hasNext())
            return 0;

        mFactorial = mFactorial * mPosition;

        mPosition++;

        return  mFactorial;
    }
}
11
Vahe Gharibyan

C'est le code complet pour écrire un itérateur tel qu'il itère sur les éléments commençant par 'a':

import Java.util.Iterator;

public class AppDemo {

    public static void main(String args[]) {

        Bag<String> bag1 = new Bag<>();

        bag1.add("alice");
        bag1.add("bob"); 
        bag1.add("abigail");
        bag1.add("charlie"); 

        for (Iterator<String> it1 = bag1.iterator(); it1.hasNext();) {

            String s = it1.next();
            if (s != null)
                System.out.println(s); 
        }
    }
}

Classe d'itérateur personnalisée

import Java.util.ArrayList;
import Java.util.Iterator;

public class Bag<T> {

    private ArrayList<T> data;

    public Bag() {

        data = new ArrayList<>();
    }

    public void add(T e) {

        data.add(e); 
    }

    public Iterator<T> iterator() {

        return new BagIterator();
    }

    public class BagIterator<T> implements Iterator<T> {

        private int index; 
        private String str;

        public BagIterator() {

            index = 0;
        }

        @Override
        public boolean hasNext() {

             return index < data.size();  
        }

        @Override
        public T next() {

            str = (String) data.get(index); 
            if (str.startsWith("a"))
                return (T) data.get(index++); 
            index++; 
            return null; 
        }
    } 
}
5
elvis

Vous pouvez implémenter votre propre itérateur. Votre itérateur peut être construit pour encapsuler l'itérateur renvoyé par la liste ou vous pouvez conserver un curseur et utiliser la méthode get de la liste (int index). Il vous suffit d'ajouter une logique à la prochaine méthode de votre itérateur ET à la méthode hasNext pour prendre en compte vos critères de filtrage. Vous devrez également décider si votre itérateur prendra en charge l'opération de suppression.

4
ditkin