Possiamo scrivere il nostro iteratore in Java?


104

Se ho una lista che contiene [alice, bob, abigail, charlie]e voglio scrivere un iteratore in modo tale che itera su elementi che iniziano con "a", posso scrivere il mio? Come lo posso fare ?


4
Puoi. Devi implementare l'interfaccia Iterator.
gd1

certo, è solo una normale interfaccia. Proxy java.util per un impl. JDO. coinvolge molti iteratori personalizzati.
bestsss

Risposte:


48

Sicuro. Un iteratore è solo un'implementazione java.util.Iteratordell'interfaccia. Se stai utilizzando un oggetto iterabile esistente (ad esempio, a LinkedList) da java.util, dovrai sottoclassarlo e sovrascrivere la sua iteratorfunzione in modo da restituire il tuo, o fornire un mezzo per avvolgere un iteratore standard nella tua Iteratoristanza speciale (che ha il vantaggio di essere utilizzato più ampiamente), ecc.


8
buona risposta .... +1 Tuttavia non sei obbligato a sottoclassare LinkedList. È possibile scrivere un CustomIterator di cui viene creata un'istanza con il nuovo CustomIterator (somelist), poiché le interfacce non dicono nulla sui costruttori.
gd1

1
@ Giacomo: Questo è ciò che intendevo con "... o fornire un mezzo per avvolgere un iteratore standard nella tua Iteratoristanza speciale ..." (e grazie). :-)
TJ Crowder

196

La migliore opzione riutilizzabile è implementare l'interfaccia Iterable e sovrascrivere il metodo iterator ().

Ecco un esempio di una classe come ArrayList che implementa l'interfaccia, in cui si sovrascrive il metodo 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;
    }
}

Questa classe implementa l'interfaccia Iterable utilizzando Generics . Considerando che hai elementi nell'array, sarai in grado di ottenere un'istanza di un Iterator, che è l'istanza necessaria utilizzata dal ciclo "foreach", per esempio.

Puoi semplicemente creare un'istanza anonima dell'iteratore senza creare extending Iterator e sfruttare il valore di currentSize per verificare fino a dove puoi navigare sull'array (supponiamo che tu abbia creato un array con capacità di 10, ma ne hai solo 2 elementi a 0 e 1). L'istanza avrà il contatore del proprietario di dove si trova e tutto ciò che devi fare è giocare con hasNext (), che verifica se il valore corrente non è nullo, e next (), che restituirà l'istanza del tuo currentIndex. Di seguito è riportato un esempio di utilizzo di questa 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

Se vuoi, puoi anche iterare su di esso usando l'istanza di 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 documentazione di foreach si trova su http://download.oracle.com/javase/1,5.0/docs/guide/language/foreach.html . Puoi dare un'occhiata a un'implementazione più completa nel mio codice Google per la pratica personale .

Ora, per ottenere gli effetti di ciò di cui hai bisogno penso che tu abbia bisogno di inserire un concetto di filtro nell'iteratore ... Poiché l'iteratore dipende dai valori successivi, sarebbe difficile restituire true su hasNext (), e poi filtra l'implementazione next () con un valore che non inizia con un carattere "a", ad esempio. Penso che tu debba giocare con un interatore secondario basato su un elenco filtrato con i valori con il filtro dato.


14
for instance, è un gioco di parole?
n611x007

4
Altre 30 persone non pensavano che fosse un gioco di parole :)
Marcello de Sales

2
È buona norma lanciare un'eccezione di operazione non supportata dai metodi implementati da noi. Penso che sia una buona idea lanciare un'eccezione di operazione non supportata dal metodo remove ()!
darshan

2
Scusami @darshan, ma questa soluzione riguarda "come scrivere iteratori" ... Se l'obiettivo fosse "scrivere codice scritto perfettamente", sarebbe lì!
Marcello de Sales

non è chiaro il motivo per cui il controllo 'arrayList [currentIndex]! = null' è richiesto all'interno di hasNext (). qualcuno può spiegare per favore.
Bhushan Karmarkar

12

Buon esempio per Iterable per il calcolo fattoriale

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

Codice breve per Java 1.8

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

Classe iterabile personalizzata

public class FactorialIterable implements Iterable<Integer> {

    private final FactorialIterator factorialIterator;

    public FactorialIterable(Integer value) {
        factorialIterator = new FactorialIterator(value);
    }

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

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

}

Classe Iteratore personalizzata

public class FactorialIterator implements Iterator<Integer> {

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


    public FactorialIterator(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;
    }
}

8

Questo è il codice completo per scrivere un iteratore in modo tale che itera su elementi che iniziano con "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 Iteratore personalizzata

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

Puoi implementare il tuo Iteratore. Il tuo iteratore potrebbe essere costruito per avvolgere l'iteratore restituito da List, oppure potresti mantenere un cursore e utilizzare il metodo get (int index) di List. Devi solo aggiungere la logica al metodo successivo del tuo Iterator E il metodo hasNext per tenere conto dei tuoi criteri di filtraggio. Dovrai anche decidere se il tuo iteratore supporterà l'operazione di rimozione.


1

Ecco la risposta completa alla domanda.

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

class ListIterator implements Iterator<String>{
    List<String> list;
    int pos = 0;

    public ListIterator(List<String> list) {
        this.list = list;
    }

    @Override
    public boolean hasNext() {
        while(pos < list.size()){
            if (list.get(pos).startsWith("a"))
                return true;
            pos++;
        }
        return false;

    }

    @Override
    public String next() {
        if (hasNext())
            return list.get(pos++);
        throw new NoSuchElementException();
    }
}

public class IteratorTest {

    public static void main(String[] args) {
        List<String> list = Arrays.asList("alice", "bob", "abigail", "charlie");
        ListIterator itr = new ListIterator(list);

        while(itr.hasNext())
            System.out.println(itr.next()); // prints alice, abigail
    }
}
  • ListIterator è l'iteratore per l'array che restituisce gli elementi che iniziano con "a".
  • Non è necessario implementare un'interfaccia Iterable. Ma questa è una possibilità.
  • Non è necessario implementarlo genericamente.
  • Soddisfa completamente il contratto per hasNext () e next (). cioè se hasNext () dice che ci sono ancora elementi, next () restituirà quegli elementi. E se hasNext () non dice più elementi, restituisce NoSuchElementExceptionun'eccezione valida .
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.