番石榴:为什么没有Lists.filter()函数?

有没有原因

Lists.transform() 

但不是

 Lists.filter() 

如何正确过滤列表? 我可以使用

 new ArrayList(Collection2.filter()) 

当然,但是这样做并不能保证我的订单保持不变,只要我理解正确。

它没有被实现,因为它会暴露大量的慢方法,例如返回的List视图上的#get(index)(引发性能错误)。 而且ListIterator也将是一个痛苦的实施(虽然我提交了一个补丁几年前,以弥补)。

由于索引方法在经过筛选的List视图中效率不高,因此最好使用过滤后的Iterable(不包含它们)。

你可以使用Iterables.filter ,它肯定会保持sorting。

请注意,通过构build新列表,您将复制元素(当然只是引用),因此它不会成为原始列表上的实时视图。 创build视图将是相当棘手的 – 考虑这种情况:

 Predicate<StringBuilder> predicate = /* predicate returning whether the builder is empty */ List<StringBuilder> builders = Lists.newArrayList(); List<StringBuilder> view = Lists.filter(builders, predicate); for (int i = 0; i < 10000; i++) { builders.add(new StringBuilder()); } builders.get(8000).append("bar"); StringBuilder firstNonEmpty = view.get(0); 

这将不得不遍历整个原始列表,将filter应用到一切。 我想这可能要求谓词匹配在视图的整个生命周期中不会改变,但是这并不是完全令人满意的。

(这只是猜测,介意你,也许其中一个番石榴维护者将切实的原因:)

我当然可以使用new List(Collection2.filter()) ,但是这样做并不能保证我的sorting保持不变。

这是不正确的。 Collections2.filter()是一个懒惰的评估函数 – 它实际上并没有过滤你的集合,直到你开始访问过滤版本。 例如,如果迭代过滤版本,那么过滤后的元素将按照与原始集合相同的顺序从迭代器中popup(显然,将被滤除的元素减去)。

也许你在想,它是先过滤,然后把结果转储成任意的,无序的某种forms的集合 – 事实并非如此。

因此,如果您使用Collections2.filter()的输出作为新列表的input,那么您的原始订单保留。

使用静态导入(和Lists.newArrayList函数),它变得相当简洁:

 List filteredList = newArrayList(filter(originalList, predicate)); 

请注意,虽然Collections2.filter不会急于迭代基础集合,但Lists.newArrayList将会提取过滤集合的所有元素,并将它们复制到新的ArrayList

正如Jon所提到的,你可以使用Iterables.filter(..)Collections2.filter(..) ,如果你不需要实时视图,你可以使用ImmutableList.copyOf(Iterables.filter(..))或者Lists.newArrayList( Iterables.filter(..))和是的sorting将被维护。

如果您确实对部分内容感兴趣,可以访问http://code.google.com/p/guava-libraries/issues/detail?id=505了解更多详情。;

总结别人说的话,你可以很容易地创build一个通用的包装来过滤列表:

 public static <T> List<T> filter(Iterable<T> userLists, Predicate<T> predicate) { return Lists.newArrayList(Iterables.filter(userLists, predicate)); }