对于我目前的大学课程,我们需要为不可变数据类型实现Iterator。到目前为止一切都那么好,没什么太糟糕的,这就是它的样子:
public Iterator<T> iterator(){
return new Iterator<T>() {
private int index = 0;
@Override
public boolean hasNext() {
//hasNext implementation
}
@Override
public T next() {
//Next Implementation
}
};
我使用了一个可变变量(index),它指向数据类型中的当前位置。练习要求我们将每个成员变量设为final(对于不可变数据类型有意义),但它还要求我们在迭代器final(index)中创建每个成员变量。这让我感到困惑,因为我没有看到在没有可变变量的情况下迭代数据类型的方法,特别是因为你无法从next()方法内部改变迭代器... 我不想要解决这个问题,我只是想知道,这是否可能,也许是一个解决方案的轻微提示......谢谢!
答案 0 :(得分:2)
如果要求每个成员变量final
是您的要求,那么可以将index
变成数组:
public Iterator<T> iterator(){
return new Iterator<T>() {
private final int[] index = {0};
// ...
};
}
因为数组元素保持可变,即使对它的引用是final
。但这只会使代码更加混乱,因为在所有地方使用index[0]
而不仅仅是index
。
迭代器本质上是可变的;我无法想到让它们变成不可变的,因为你希望在你使用它们时改变它们。
请注意,简单地使所有成员变量final
确实使类型不可变。成员变量还必须引用深度不可变的对象;非零长度数组不能完全不可变,因为你总是可以重新分配它们的元素。
答案 1 :(得分:0)
注意:我对Java并不是很熟悉,并且基于我在C#中所做的事情,但我会有所作为。
注意:我现在忽略了“仅提示”请求,因为它现在要晚得多,所以我假设这不再适用。否则,请不要超出第一个代码示例(包括或排除,直至您)。
你可以通过创建一个迭代器类型来解决这个问题,每次移动到下一个元素时都会返回一个新的迭代器对象。因此,基本上,每次移动 - 下一步操作都将返回三件事:
这种设计的优点是你可以在任何时候停止迭代,然后从那一点开始继续 - 而不必首先遍历集合的先前元素。使用.NET LINQ方法,例如Where()或OrderBy(),这可能需要大量处理来再次迭代先前的元素,这在某些情况下可能非常有用。
但是,这种新模式不支持内置功能(例如foreach和LINQ的Java等价物)。此外,迭代器对象应该是一种值类型以提高性能(因为为集合中的每个项创建了一个新实例),但Java不支持自定义值类型。因此,Java模式可能类似于:
interface IterationItem<T> {
public T getValue();
public boolean hasNext();
public IterationItem<T> next();
}
实现如下:
class ListIterationItem<T> implements IterationItem<T>
{
private List<T> _list; // Could be public (so long as it's read-only)
private int _index; // ^
private T _value;
public ListIterationItem(List<T> list, int index) {
_list = list;
_index = index;
_value = list[index];
}
public T getValue() { return _value; } //Or look up the value on-demand, idk which is better
public boolean hasNext() {
return _index + 1 < _list.size())
}
public IterationItem<T> next() {
return new ListIterationItem<T>(_list, _index + 1);
}
}
您可以这样使用:
List<String> list = Arrays.asList("aaa", "bbb", "ccc");
IterationItem<String> item = new ListIterationItem<String>(list, 0);
while (true) {
String current = item.getValue();
//Do something with the current value
if (item.hasNext()) { item = item.next(); }
};
或者,如果你真的需要避免修改任何字段(例如,当使用不允许你的语言时),你可以使用递归:
void Main() {
List<String> list = Arrays.asList("aaa", "bbb", "ccc");
ProcessElements(new ListIterationItem<String>(list, 0));
}
void ProcessElements(IterationItem<T> item) {
String current = item.getValue();
//Do something with the current value
if (item.hasNext()) {
ProcessElements(item.next());
}
}
您还可以编写一个方法来将这种迭代器包装为普通迭代器,以便它可以用于for-each循环等等:
public static Iterable<T> AsIterable<T>(IterationItem<T> item)
return new Iterable<T>() {
@Override
public Iterator<T> iterator() {
return new Iterator<String>() {
private IterationItem<T> currentItem = item; //Idk if this works
@Override
public boolean hasNext() {
return item.hasNext();
}
@Override
public String next() {
item = item.next();
return item.getValue();
}
@Override
public void remove() { throw new UnsupportedOperationException(); }
};
}
};
}
我考虑到这个想法来到这里,然后决定研究它 - 但这是我到目前为止找到的最相关的页面,所以我想我会记下我的想法。如果有人知道类似的东西,我有兴趣知道。