Внедрить Java Iterator и Iterable в том же классе?
Я пытаюсь понять интерфейсы 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();
}
}
Какой из них лучше?
Ответы
Ответ 1
Вы почти никогда не должны использовать как Iterable
, так и Iterator
в том же классе. Они делают разные вещи. Итератор естественно с точки зрения состояния - поскольку вы итерации используете его, он должен обновить свой взгляд на мир. Итерабельный, однако, должен только иметь возможность создавать новые итераторы. В частности, у вас может быть несколько итераторов, работающих одновременно над одним и тем же оригиналом.
Ваш нынешний подход в значительной степени в порядке - есть аспекты реализации, которые я бы изменил, но это прекрасно с точки зрения разделения обязанностей.
Ответ 2
Вы были на пути с первой попытки. MyClass
нужно реализовать Iterable<String>
, что, в свою очередь, требует от Iterator<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();
}
};
}
}
Ответ 3
Вы не должны делать Myclass implements Iterable<String>,Iterator<String>{
, так как итераторы одноразового использования. За исключением итераторов списка, нет способа вернуть их к началу.
Кстати, вы можете пропустить
MyClass myClass;
public MyClassInterator(MyClass m){
myclass=m;
}
и вместо ссылки
myClass
ссылка
MyClass.this
Ваш внутренний класс не является статическим, поэтому MyClass.this
будет ссылаться на экземпляр окружающего класса, который его создал.