Реализовать Java Iterator и Iterable в одном классе? - PullRequest
15 голосов
/ 29 апреля 2011

Я пытаюсь понять интерфейсы Java Iterator и Iterable

Я пишу этот класс

class MyClass implements Iterable<String> {
    public String[] a = null;
    public MyClass(String[] arr) {
        a = arr;    
    }

    public MyClassIterator iterator() {
        return new MyClassIterator(this);
    }

    public class MyClassIterator implements Iterator<String> {
        private MyClass myclass = null;
        private int count = 0;
        public MyClassIterator(MyClass m) {
            myclass = m;    
        }

        public boolean hasNext() {
            return count < myclass.a.length;
        }
        public String next() {
            int t = count;
            count++;
            return myclass.a[t];
        }

        public void remove() {
            throw new UnsupportedOperationException();
        }
    }   
}

Кажется, работает.

Должен ли я иметь:

Myclass implements Iterable<Stirng>, Iterator<String> {

}

Или я должен поставить MyClassIterator снаружи MyClass как

class MyClass implements Iterable<String> {
    public String[] a = null;
    public MyClass(String[] arr) {
        a = arr;    
    }
    public MyClassIterator iterator() {
        return new MyClassIterator(this);
    }
}


    public class MyClassIterator implements Iterator<String> {
        private MyClass myclass = null;
        private int count = 0;
        public MyClassIterator(MyClass m) {
            myclass = m;    
        }

        public boolean hasNext() {
            return count < myclass.a.length;
        }
        public String next() {
            int t = count;
            count++;
            return myclass.a[t];
        }

        public void remove() {
            throw new UnsupportedOperationException();
        }
    }   

Какой из них лучше?

Ответы [ 4 ]

33 голосов
/ 29 апреля 2011

Вы должны почти никогда реализовать оба Iterable и Iterator в одном классе.Они делают разные вещи.Итератор, естественно, с состоянием - когда вы выполняете итерацию, используя его, он должен обновить свое представление о мире.Итерируемый, однако, только должен иметь возможность создавать новые итераторы.В частности, у вас может быть несколько итераторов, работающих над одним и тем же исходным итерируемым в одно и то же время.

Ваш нынешний подход в значительной степени хорош - есть аспекты реализации, которые я бы изменил, но это нормально с точки зренияразделение обязанностей.

7 голосов
/ 29 апреля 2011

Вы были на ходу с первой попытки.MyClass требуется только для реализации Iterable<String>, что, в свою очередь, требует от вас Iterator<String> реализации для возврата из Iterable<String>.iterator().

Нет необходимости ставить MyClassIterator вне MyClass, потому что в большинстве случаев вам даже никогда не понадобится напрямую использовать Iterator<String> (он неявно используется синтаксисом for .. in .. для Iterable<String>s) и во всех других случаях интерфейс является достаточным, если вы фактически не добавите в реализацию дополнительное поведение (что вам, вероятно, никогда не понадобится).

Вот как я это сделаю, см. комментариивстроенный:

import java.util.Iterator;

class MyClass implements Iterable<String>{
    public String[] a=null; //make this final if you can
    public MyClass(String[] arr){
        a=arr; //maybe you should copy this array, for fear of external modification
    }

    //the interface is sufficient here, the outside world doesn't need to know
    //about your concrete implementation.
    public Iterator<String> iterator(){
        //no point implementing a whole class for something only used once
        return new Iterator<String>() {
            private int count=0;
            //no need to have constructor which takes MyClass, (non-static) inner class has access to instance members
            public boolean hasNext(){
                //simplify
                return count < a.length;
            }
            public String next(){
                return a[count++]; //getting clever
            }

            public void remove(){
                throw new UnsupportedOperationException();
            }
        };
    }
}
2 голосов
/ 29 апреля 2011

Вы не должны делать Myclass implements Iterable<String>,Iterator<String>{, так как итераторы являются одноразовыми. За исключением итераторов списков, невозможно вернуть их в начало.

Кстати, вы можете пропустить

MyClass myClass;
public MyClassInterator(MyClass m){
  myclass=m;  
}

и вместо ссылки

myClass

ссылка

MyClass.this

Ваш внутренний класс не является статическим, поэтому MyClass.this будет ссылаться на экземпляр класса, который его создал.

0 голосов
/ 09 апреля 2018

Полагаю, это стандартный способ одновременной реализации Iterable и Iterator.

// return list of neighbors of v
public Iterable<Integer> adj(int v) {
    return new AdjIterator(v);
}

// support iteration over graph vertices
private class AdjIterator implements Iterator<Integer>, Iterable<Integer> {
    private int v;
    private int w = 0;

    AdjIterator(int v) {
        this.v = v;
    }

    public Iterator<Integer> iterator() {
        return this;
    }

    public boolean hasNext() {
        while (w < V) {
            if (adj[v][w]) return true;
            w++;
        }
        return false;
    }

    public Integer next() {
        if (!hasNext()) {
            throw new NoSuchElementException();
        }
        return w++;
    }

Ссылка https://algs4.cs.princeton.edu/41graph/AdjMatrixGraph.java.html.

...