Можем ли мы написать свой собственный итератор на Java? - PullRequest
87 голосов
/ 01 мая 2011

Если у меня есть список, содержащий [alice, bob, abigail, charlie], и я хочу написать итератор так, чтобы он перебирал элементы, начинающиеся с «а», могу ли я написать свой собственный? Как я могу это сделать ?

Ответы [ 5 ]

177 голосов
/ 01 мая 2011

Лучший вариант многократного использования - реализовать интерфейс Iterable и переопределить метод iterator ().

Вот пример класса, похожего на ArrayList, реализующего интерфейс, в котором вы переопределяете метод 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;
    }
}

Этот класс реализует интерфейс Iterable с использованием Generics . Учитывая, что у вас есть элементы в массиве, вы сможете получить экземпляр Iterator, который является необходимым экземпляром, используемым, например, циклом «foreach».

Вы можете просто создать анонимный экземпляр итератора, не создавая расширяющий итератор, и воспользоваться значением currentSize, чтобы проверить, где вы можете перемещаться по массиву (скажем, вы создали массив с емкостью 10, но вы есть только 2 элемента в 0 и 1). Экземпляр будет иметь свой счетчик владельцев, где он находится, и все, что вам нужно сделать, это поиграть с hasNext (), который проверяет, не является ли текущее значение не нулевым, и next (), который вернет экземпляр вашего currentIndex. Ниже приведен пример использования этого 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

Если вы хотите, вы можете итерировать по нему, используя экземпляр 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

Документация foreach находится по адресу http://download.oracle.com/javase/1,5.0/docs/guide/language/foreach.html. Более детальную реализацию вы можете найти в моей личной практике google code .

Теперь, чтобы получить эффект от того, что вам нужно, я думаю, вам нужно подключить концепцию фильтра в Итераторе ... Поскольку итератор зависит от следующих значений, было бы трудно вернуть true в hasNext () и затем отфильтруйте реализацию next () по значению, которое не начинается, например, с символа "a". Я думаю, что вам нужно поиграть со вторым Интератором на основе отфильтрованного списка со значениями с данным фильтром.

40 голосов
/ 01 мая 2011

Конечно. Итератор - это просто реализация интерфейса java.util.Iterator. Если вы используете существующий итерируемый объект (скажем, LinkedList) из java.util, вам необходимо либо создать подкласс для него и переопределить его функцию iterator, чтобы вернуть свой собственный, либо предоставить средство обтекания стандартный итератор в вашем особом экземпляре Iterator (который имеет преимущество в более широком использовании) и т. д.

11 голосов
/ 19 декабря 2016

Хороший пример для Iterable для вычисления факториала

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

краткий код для Java 1.8

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

настраиваемый итерируемый класс

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

}

пользовательский класс Iterator

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;
    }
}
6 голосов
/ 19 мая 2018

Это полный код для написания итератора, который перебирает элементы, начинающиеся с '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); 
        }
    }
}

Пользовательский класс Iterator

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; 
        }
    } 
}
4 голосов
/ 01 мая 2011

Вы можете реализовать свой собственный итератор.Ваш итератор может быть создан для переноса итератора, возвращаемого списком, или вы можете держать курсор и использовать метод get (int index) списка.Вам просто нужно добавить логику в следующий метод вашего Итератора И метод hasNext, чтобы учесть ваши критерии фильтрации.Вам также придется решить, будет ли ваш итератор поддерживать операцию удаления.

...