Mettre en œuvre Java Iterator et Iterable dans la même classe?
Question
Je suis en train de comprendre les interfaces Java Iterator
et Iterable
Je suis en train d'écrire cette classe
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();
}
}
}
Il semble fonctionner.
que je devrais faire:
Myclass implements Iterable<Stirng>, Iterator<String> {
}
Ou devrais-je mettre MyClassIterator
en dehors MyClass
comme
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();
}
}
Quelle est la meilleure?
La solution
Vous devriez presque jamais mettre en œuvre à la fois Iterable
et Iterator
dans la même classe. Ils font des choses différentes. Itérateur est naturellement stateful - comme vous itérer l'utiliser, il doit mettre à jour sa vision du monde. Un itératives, cependant, ne doit être en mesure de créer de nouveaux itérateurs. En particulier, vous pourriez avoir plusieurs itérateurs travaillant sur le même original itérables en même temps.
Votre approche actuelle est à peu près correct -. Il y a des aspects de la mise en œuvre que je changerais, mais il va bien en termes de la séparation des responsabilités
Autres conseils
Vous étiez sur la bonne voie avec votre premier essai. MyClass
n'a besoin que de mettre en œuvre Iterable<String>
, ce qui vous oblige à fournir une implémentation de Iterator<String>
revenir de Iterable<String>.iterator()
.
Il n'y a pas besoin de mettre à l'extérieur de MyClassIterator
de MyClass
parce que dans la plupart des cas, vous ne même pas besoin d'utiliser directement le Iterator<String>
(il est utilisé implicitement par la syntaxe for .. in ..
sur Iterable<String>
s), et dans tous les autres cas, l'interface est suffisante, à moins que vous en fait ajouter un comportement supplémentaire à la mise en œuvre (que vous aurez probablement jamais besoin de faire).
Voici comment je le ferais, voir les commentaires inline:
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();
}
};
}
}
Vous ne devriez pas faire Myclass implements Iterable<String>,Iterator<String>{
depuis itérateurs sont à usage unique. À l'exception des itérateurs de la liste, il n'y a aucun moyen de les retourner au début.
Par ailleurs, vous pouvez sauter la
MyClass myClass;
public MyClassInterator(MyClass m){
myclass=m;
}
et au lieu de référencer
myClass
référence
MyClass.this
Votre classe interne n'est pas statique, MyClass.this
fera référence à l'instance de la classe de fermeture qui l'a créé.
Je suppose que c'est un moyen standard pour mettre en œuvre le Iterable et Iterator en même temps.
// 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++;
}
Référence https://algs4.cs.princeton.edu/41graph/ AdjMatrixGraph.java.html .