Zaimplementować Java Iterator i Iterable w tej samej klasie?

Próbuję zrozumieć Interfejsy Javy Iterator iIterable

Piszę tę klasę

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();
        }
    }   
}
Wygląda na to, że działa.

Powinienem:

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

}

Lub powinienem umieścić MyClassIterator na zewnątrz MyClass jako

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();
        }
    }   
Która jest lepsza?
Author: Lii, 2011-04-29

4 answers

Powinieneś prawie nigdy implementować zarówno Iterable jak i Iterator w tej samej klasie. Robią różne rzeczy. Iterator jest naturalnie stateful - gdy iterator używa go, musi zaktualizować swój pogląd na świat. Iterable, jednak tylko musi być w stanie tworzyć nowe Iteratory. W szczególności, możesz mieć kilka iteratorów pracujących nad tą samą oryginalną iteracją w tym samym czasie.

Twoje obecne podejście jest prawie w porządku - istnieją aspekty wdrożenia Zmieniłbym się, ale jest w porządku, jeśli chodzi o podział obowiązków.

 33
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-29 19:00:10

Byłeś na dobrej drodze przy pierwszej próbie. MyClass musi jedynie zaimplementować Iterable<String>, co z kolei wymaga dostarczenia Iterator<String> implementacji do powrotu z Iterable<String>.iterator().

Nie ma potrzeby umieszczania MyClassIterator poza MyClass, ponieważ w większości przypadków nigdy nie będziesz musiał bezpośrednio używać Iterator<String> (jest ona używana domyślnie przez składnię for .. in .. na Iterable<String>s), a we wszystkich innych przypadkach interfejs jest wystarczający, chyba że faktycznie dodasz dodatkowe zachowanie do implementacji (co prawdopodobnie nie będzie nigdy nie trzeba).

Oto jak bym to zrobił, Zobacz komentarze:

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();
            }
        };
    }
}
 7
Author: Stephen Swensen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-29 20:00:50

Nie powinieneś robić Myclass implements Iterable<String>,Iterator<String>{, ponieważ Iteratory są jednorazowego użytku. Z wyjątkiem iteratorów list, nie ma możliwości powrotu ich do początku.

Nawiasem mówiąc, możesz pominąć

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

I zamiast odwoływać się

myClass

Odniesienie

MyClass.this

Twoja wewnętrzna klasa nie jest statyczna, więc MyClass.this będzie odwoływać się do instancji klasy, która ją utworzyła.

 2
Author: Mike Samuel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-29 19:01:30

Przypuszczam, że jest to standardowy sposób implementacji Iterable i Iterator w tym samym czasie.

// 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++;
    }

Odniesienie https://algs4.cs.princeton.edu/41graph/AdjMatrixGraph.java.html .

 0
Author: 8cold8hot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-19 04:41:13