java为什么在Guava filter/transform函数中有时返回可修改的视图,而有些返回不可修改的视图?
例如,所有列表、集合2、集合返回可修改的视图-从视图集合中删除将删除原始项
这很好:
List<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5, 6, -1, -2, -3, -4);
Collection<Integer> transform = Collections2.filter(
list, new Predicate<Integer>() {
public boolean apply(Integer input) {
return input.intValue() > 0;
}
});
transform.clear();
当我使用Iterables和Iterators方法filter/transform时,我得到了一个可修改的视图(即所有这些代码重用不可修改的iterator)
这不管用:
List<Integer> list = Lists.newArrayList(1, 2, 3, 4, 5, 6, -1, -2, -3, -4);
Iterable<Integer> transform = Iterables.filter(
list, new Predicate<Integer>() {
public boolean apply(Integer input) {
return input.intValue() > 0;
}
});
Iterables.removeIf(transform, Predicates.<Object>alwaysTrue());
我在Iterable和Collection/List/Set/Map之间找不到任何语义上的差异,那么为什么在Guava中有如此不同的实现呢
另一个奇怪的行为是,在第一种情况下,迭代器仍然不允许删除操作,但clear或remove/removeAll可以正常工作
# 1 楼答案
Iterators.transform
(扩展为Iterables.transform
)确实支持remove()
。从其Javadoc:然而
Iterators.filter
没有。这是因为过滤迭代器无法在不调用底层迭代器上的next()
的情况下实现hasNext()
。在基础迭代器上调用hasNext()
是不够的,因为该迭代器中的下一个元素(以及之后的每个元素,可能)可能与Predicate
不匹配那么,问题是在过滤的迭代器上调用
hasNext()
必须提升底层迭代器的位置。这可以防止对remove()
的后续调用删除最近对next()
的调用返回的元素(这是remove()
契约的一部分)。因此,在过滤迭代器上不支持remove()
过滤的
Collection
的Iterator
有完全相同的问题(实际上,它是使用Iterators.filter
创建的)。clear()
和removeAll
方法之所以有效,是因为它们完全控制迭代器(它们都是使用Iterables.removeIf
实现的)