我想根据谓词筛选java.util.Collection。


当前回答

使用来自Apache Commons的CollectionUtils.filter(Collection,Predicate)。

其他回答

使用来自Apache Commons的CollectionUtils.filter(Collection,Predicate)。

让我们看看如何使用Eclipse Collections筛选内置JDK List和MutableList。

List<Integer> jdkList = Arrays.asList(1, 2, 3, 4, 5);
MutableList<Integer> ecList = Lists.mutable.with(1, 2, 3, 4, 5);

如果希望过滤小于3的数字,则会得到以下输出。

List<Integer> selected = Lists.mutable.with(1, 2);
List<Integer> rejected = Lists.mutable.with(3, 4, 5);

下面介绍如何使用Java 8 lambda作为Predicate进行筛选。

Assert.assertEquals(selected, Iterate.select(jdkList, each -> each < 3));
Assert.assertEquals(rejected, Iterate.reject(jdkList, each -> each < 3));

Assert.assertEquals(selected, ecList.select(each -> each < 3));
Assert.assertEquals(rejected, ecList.reject(each -> each < 3));

下面介绍如何使用匿名内部类作为Predicate进行筛选。

Predicate<Integer> lessThan3 = new Predicate<Integer>()
{
    public boolean accept(Integer each)
    {
        return each < 3;
    }
};

Assert.assertEquals(selected, Iterate.select(jdkList, lessThan3));
Assert.assertEquals(selected, ecList.select(lessThan3));

下面是一些使用Predicates工厂过滤JDK列表和Eclipse Collections mutabllists的替代方案。

Assert.assertEquals(selected, Iterate.select(jdkList, Predicates.lessThan(3)));
Assert.assertEquals(selected, ecList.select(Predicates.lessThan(3)));

下面是一个不为谓词分配对象的版本,而是使用Predicates2工厂,并使用selectWith方法接受Predicate2。

Assert.assertEquals(
    selected, ecList.selectWith(Predicates2.<Integer>lessThan(), 3));

有时你想过滤一个消极的条件。在Eclipse Collections中有一个特殊的方法叫做reject。

Assert.assertEquals(rejected, Iterate.reject(jdkList, lessThan3));
Assert.assertEquals(rejected, ecList.reject(lessThan3));

方法分区将返回两个集合,包含Predicate选择和拒绝的元素。

PartitionIterable<Integer> jdkPartitioned = Iterate.partition(jdkList, lessThan3);
Assert.assertEquals(selected, jdkPartitioned.getSelected());
Assert.assertEquals(rejected, jdkPartitioned.getRejected());

PartitionList<Integer> ecPartitioned = gscList.partition(lessThan3);
Assert.assertEquals(selected, ecPartitioned.getSelected());
Assert.assertEquals(rejected, ecPartitioned.getRejected());

注意:我是Eclipse Collections的提交者。

考虑使用支持泛型的更新的Collections框架谷歌Collections。

更新:谷歌集合库现在已弃用。你应该使用最新发布的番石榴。它仍然具有对集合框架的所有相同扩展,包括基于谓词进行筛选的机制。

Java集合流的一个替代(更轻量级的)选择是Ocl.java库,它使用vanilla集合和lambdas: https://github.com/eclipse/agileuml/blob/master/Ocl.java

例如,对数组列表中的单词进行简单的筛选和求和 可能是:

ArrayList<Word> sel = Ocl.selectSequence(words, 
                             w -> w.pos.equals("NN")); 
int total = Ocl.sumint(Ocl.collectSequence(sel,
                             w -> w.text.length())); 

Where Word有字符串pos;字符串文本;属性。效率似乎与流选项相似,例如,在两个版本中,10000个单词在大约50毫秒内处理。

Python、Swift等都有等效的OCL库。基本上,Java集合流重新发明了OCL操作——>select, ->collect等,这些操作自1998年以来就存在于OCL中。

Java 8(2014)在一行代码中使用流和lambdas解决了这个问题:

List<Person> beerDrinkers = persons.stream()
    .filter(p -> p.getAge() > 16).collect(Collectors.toList());

这是一个教程。

使用Collection#removeIf在适当的地方修改集合。(注意:在这种情况下,谓词将删除满足谓词的对象):

persons.removeIf(p -> p.getAge() <= 16);

Lambdaj允许在不编写循环或内部类的情况下过滤集合:

List<Person> beerDrinkers = select(persons, having(on(Person.class).getAge(),
    greaterThan(16)));

你能想象出更有可读性的东西吗?

免责声明:我是lambdaj的贡献者