对于我的应用程序,元素访问很昂贵,所以java.util.Iterator没用。我想要更像C ++迭代器的东西,我可以在不返回元素的情况下移动指针。这样的标准库中有什么东西,或者是否有通过自定义演变的事实上的标准接口? (如果没有,请不要浪费时间发布代码片段 - 我完全能够想出合理的名字来完成这项工作)。
答案 0 :(得分:2)
java.util.Iterator是一个接口,而不是一个实现。迭代器的行为取决于您使用的集合以及如何获取它。
大多数人不应该做任何昂贵的事情,因为对于Objects,Java传递他们的引用。无论您访问的是什么,都是昂贵的,应该在一个Object之后抽象出来,允许您在不试图访问它的情况下引用它。
如果您的抱怨与界面相关并且需要其他方法,那么您需要自己提出并遵循该界面; java.util.Iterator 是 Java的传统迭代器,部分原因可能是我提到过。
答案 1 :(得分:0)
(由于没有人来写一个正确的答案,我会将我的评论扩展为答案。)
据我所知,标准API中没有适合您的界面(即iterator.skip()
之类的界面)。我认为,使用标准API方法的最佳解决方案是yourList.sublist(startIndex).iterator()
。
我认为,如果可能的话,您应该考虑创建自己的迭代器接口。 (注意,如果需要,可以让它扩展java.util.Iterator
接口,以便能够将它用作普通迭代器。)
最后,这主要是为了让未来的读者 使用java.util.Iterator
而 来懒惰地访问基础列表,您可以使用{{ 3}}。请注意,Proxy
对象并不能始终与序列化/持久性库一起使用,并且它要求您使用接口。一个例子如下:
这是慢 OnDiskList
,在每次get(int n)
的调用中取 n 行:
class OnDiskList extends AbstractList<CharSequence> {
// Slow list access method: Linear search for n:th line.
@Override
public CharSequence get(int n) {
System.out.println("Fetching line " + n + "...");
try (Stream<String> lines = Files.lines(Paths.get("big-file.txt"))) {
return lines.skip(n).findFirst().get();
} catch (IOException shouldBeHandled) {
return null;
}
}
@Override
public int size() {
return 5;
}
}
以下是使用普通迭代器时输出的外观:
Iterator<CharSequence> normalIter = onDiskList.iterator();
normalIter.next(); // Skip
normalIter.next(); // Skip
normalIter.next(); // Skip
System.out.println(normalIter.next()); // Print
<强>输出:强>
Fetching line 0...
Fetching line 1...
Fetching line 2...
Fetching line 3...
Line 3 in big-file.txt
现在到了魔法:这里有一个ProxyingIterator
隐藏了Proxy
后面的对象,它懒洋洋地访问列表:
class ProxyingIterator implements Iterator<CharSequence> {
List<CharSequence> slowList;
int pos = 0;
public ProxyingIterator(List<CharSequence> slowList) {
this.slowList = slowList;
}
@Override
public boolean hasNext() {
return pos < slowList.size();
}
@Override
public CharSequence next() {
return (CharSequence) Proxy.newProxyInstance(
CharSequence.class.getClassLoader(),
new Class[] { CharSequence.class },
new LazyLoadingInvocationHandler(pos++));
}
private class LazyLoadingInvocationHandler implements InvocationHandler {
int index;
CharSequence loadedObject = null;
public LazyLoadingInvocationHandler(int index) {
this.index = index;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
if (loadedObject == null)
loadedObject = slowList.get(index);
try {
return method.invoke(loadedObject, args);
} catch (Exception shouldNotHappen) {
shouldNotHappen.printStackTrace();
return null;
}
}
}
}
使用此迭代器时,它看起来如下:
Iterator<CharSequence> proxyingIter = new ProxyingIterator(onDiskList);
proxyingIter.next(); // Skip
proxyingIter.next(); // Skip
proxyingIter.next(); // Skip
System.out.println(proxyingIter.next()); // Print
<强>输出:强>
Fetching line 3...
Line 3 in big-file.txt