Mar*_*ers 32 java foreach guava
当增强的for循环(foreach循环)被添加到Java时,它可以使用数组或目标Iterable.
for ( T item : /*T[] or Iterable<? extends T>*/ ) {
//use item
}
Run Code Online (Sandbox Code Playgroud)
这对于仅实现一种迭代类型的Collection类非常有用,因此只有一个iterator()方法.
但是我发现自己非常沮丧地想要使用Collection类中的非标准迭代器.例如,我最近试图帮助某人使用a Deque作为LIFO /堆栈,然后按FIFO顺序打印元素.我被迫这样做:
for (Iterator<T> it = myDeque.descendingIterator(); it.hasNext(); ) {
T item = it.next();
//use item
}
Run Code Online (Sandbox Code Playgroud)
我失去了for-each循环的优点.这不仅仅是击键.如果我不需要,我不喜欢暴露迭代器,因为很容易犯it.next()两次调用等错误.
理想情况下,我认为for-each循环应该也接受了Iterator.但事实并非如此.那么在这些情况下是否存在使用for-each循环的惯用方法?我也很想听到使用像Guava这样的常见集合库的建议.
我能想出的最好的帮助方法/类是:
for ( T item : new Iterable<T>() { public Iterator<T> iterator() { return myDeque.descendingIterator(); } } ) {
//use item
}
Run Code Online (Sandbox Code Playgroud)
哪个不值得使用.
我很想看到番石榴有类似的东西Iterables.wrap,但没有找到类似的东西.显然,我可以通过类或辅助方法滚动我自己的Iterator包装器.还有其他想法吗?
编辑:作为旁注,任何人都可以给出一个有效的理由,说明为什么增强的for循环不应该只接受一个Iterator?让我使用当前的设计可能会有很长的路要走.
Mar*_*ers 28
我想从各种答案中收集一些潜在的原因,为什么for-each循环不会简单地接受迭代器.
for ( Row r : table )意味着极其可读,因为"对于表中的每一行"r"......".看到for ( Row r : table.backwardsIterator() )可读性的断裂.Iterable 又是a Iterator,那么行为是什么?虽然很容易制定一致的规则(例如Iterator之前的Iterable),但开发人员的行为将变得不那么透明.此外,必须在编译时检查这一点.Iterator并限制其范围到循环.有两种方式这使得循环"只读":它不公开的迭代器,这意味着什么(很容易),有形,有它改变状态的循环,也可以改变操作数的状态中循环(正如你可以通过直接与Iterator接口remove()).自己传递迭代器必然意味着迭代器被暴露,使你失去循环的那些"只读"属性.Col*_*inD 16
我可能会做的只是创建一个Deques可以支持它的实用程序类,以及其他实用程序(如果需要).
public class Deques {
private Deques() {}
public static <T> Iterable<T> asDescendingIterable(final Deque<T> deque) {
return new Iterable<T>() {
public Iterator<T> iterator() {
return deque.descendingIterator();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是另一种情况,我们还没有lambda和方法引用真的太糟糕了.在Java 8中,您将能够编写类似这样的内容,因为方法引用descendingIterator()与以下内容的签名匹配Iterable:
Deque<String> deque = ...
for (String s : deque::descendingIterator) { ... }
Run Code Online (Sandbox Code Playgroud)
不是创建一个descendingIterator,而是编写一个descendingIterable()方法来返回基于deque的降序迭代,这基本上取代了你的匿名类.这对我来说似乎很合理.根据Colin的建议,此方法返回的可迭代实现将descendingIterator在每次调用自己的iterator()方法时调用原始deque .
如果你只有一个迭代器并希望保持这种方式,你必须编写一个Iterable<T>包含迭代器的实现并将其返回一次,如果iterator()被多次调用则抛出异常.这样可行,但显然很难看.
Java 8(作为一种冗长的语言)中的惯用方式是这样的:
for (T t : (Iterable<T>) () -> myDeque.descendingIterator()) {
// use item
}
Run Code Online (Sandbox Code Playgroud)
即包装Iterator在Iterablelambda 中。这几乎是您自己使用匿名类所做的,但使用 lambda 会更好一些。
当然,你总是可以诉诸于使用Iterator.forEachRemaining():
myDeque.descendingIterator().forEachRemaining(t -> {
// use item
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
9749 次 |
| 最近记录: |