为什么Guava过滤器/转换函数有时返回可修改的视图,有些返回不可修改的视图?

时间:2011-07-15 12:57:35

标签: java guava

例如,所有Lists,Collections2,Sets都返回一个可修改的视图 - 从视图集合中删除将删除原始项目。

这很好用:

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方法过滤/转换时,我得到umodifiable视图(即所有这些代码重用UnmodifibleIterator)。

这不起作用:

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 个答案:

答案 0 :(得分:10)

Iterators.transform(和Iterables.transform,扩展名)确实支持remove()。来自它的Javadoc:

  

如果提供的迭代器有,则返回的迭代器支持remove()

然而,

Iterators.filter没有。这样做的原因是,如果没有在底层迭代器上调用hasNext(),则过滤迭代器无法实现next()。在底层迭代器上调用hasNext()是不够的,因为迭代器中的下一个元素(以及之后的每个元素,可能)都可能与Predicate不匹配。

问题是,在筛选的迭代器上调用hasNext()必须提升底层迭代器的位置。这可以防止后续调用remove()删除最近一次调用next()(这是remove()合同的一部分)返回的元素。因此,在过滤的迭代器上不能支持remove()

已过滤的Iterator的{​​{1}}具有完全相同的问题(事实上,它是使用Collection创建的)。 Iterators.filterclear()方法有效,因为它们可以完全控制迭代器(它们都是使用removeAll实现的)。