我想知道为什么 Iterable
接口不提供 stream()
和 parallelStream()
方法 . 考虑以下课程:
public class Hand implements Iterable<Card> {
private final List<Card> list = new ArrayList<>();
private final int capacity;
//...
@Override
public Iterator<Card> iterator() {
return list.iterator();
}
}
这是一个Hand的实现,因为你可以在玩卡片游戏时手中拿着牌 .
基本上它包装 List<Card>
,确保最大容量并提供一些其他有用的功能 . 将它直接实现为 List<Card>
会更好 .
现在,为了方便起见,我认为实现 Iterable<Card>
会很好,这样如果你想循环它就可以使用增强的for循环 . (我的 Hand
类也提供了 get(int index)
方法,因此 Iterable<Card>
在我看来是合理的 . )
Iterable
接口提供以下内容(省略javadoc):
public interface Iterable<T> {
Iterator<T> iterator();
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
default Spliterator<T> spliterator() {
return Spliterators.spliteratorUnknownSize(iterator(), 0);
}
}
现在可以获得一个流:
Stream<Hand> stream = StreamSupport.stream(hand.spliterator(), false);
所以关于真正的问题:
- 为什么
Iterable<T>
没有提供实现stream()
和parallelStream()
的默认方法,我什么都看不到会导致这种不可能或不需要的东西?
我找到的一个相关问题如下:Why does Stream<T> not implement Iterable<T>?
奇怪的是,这表明它在某种程度上是相反的 .
3 回答
我在几个项目lambda邮件列表中进行了调查,我想我发现了一些有趣的讨论 .
到目前为止,我还没有找到令人满意的解释 . 读完这一切之后我得出结论,这只是一个遗漏 . 但是你可以在这里看到,在API的设计过程中多年来已经多次讨论过它 .
Lambda Libs Spec Experts
我在Lambda Libs Spec Experts mailing list找到了关于这个问题的讨论:
根据Iterable/Iterator.stream() Sam Pullara说:
然后Brian Goetz responded:
And later
Previous Discussions in Lambda Mailing List
这可能不是您正在寻找的答案,但在Project Lambda mailing list中对此进行了简要讨论 . 也许这有助于促进关于这一主题的更广泛的讨论 .
用Brian Goetz的话说Streams from Iterable:
Contradiction?
虽然看起来讨论是基于专家组对最初基于迭代器的Streams的初始设计所做的更改 .
即便如此,有趣的是注意到在像Collection这样的接口中,stream方法定义为:
哪一个可能与Iterable接口中使用的代码完全相同 .
所以,这就是为什么我说这个答案可能并不令人满意,但对于讨论仍然很有意思 .
Evidence of Refactoring
继续在邮件列表中进行分析,看起来splitIterator方法最初位于Collection界面中,并且在2013年的某些时候,它们将其移动到Iterable .
Pull splitIterator up from Collection to Iterable .
Conclusion/Theories?
那么Iterable中缺少方法可能只是一个遗漏,因为看起来他们应该在将splitIterator从Collection移动到Iterable时移动了stream方法 .
如果还有其他原因则不明显 . 别人有其他理论吗?
这不是遗漏; 2013年6月对EG清单进行了详细讨论 .
对专家组的最终讨论植根于this thread .
虽然"obvious"(最初是专家组)似乎
stream()
似乎在Iterable
上有意义,但Iterable
如此普遍的事实成了一个问题,因为明显的签名:并不总是你想要的 . 例如,
Iterable<Integer>
的某些内容宁愿使其stream方法返回IntStream
. 但是将stream()
方法放在层次结构中会使这个问题变得不可能 . 因此,通过提供spliterator()
方法,我们可以很容易地从Iterable
创建一个Stream
.Collection
中stream()
的实现只是:任何客户端都可以从
Iterable
获取他们想要的流:最后我们得出结论,将
stream()
添加到Iterable
将是一个错误 .如果您知道大小,可以使用
java.util.Collection
,它提供stream()
方法:然后:
我遇到了同样的问题,并且很惊讶我的
Iterable
实现可以通过简单地添加size()
方法很容易地扩展到AbstractCollection
实现(幸运的是我有收集的大小:-)您还应该考虑覆盖
Spliterator<E> spliterator()
.