public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
Collection<T> result = new ArrayList<T>();
for (T element: target) {
if (predicate.apply(element)) {
result.add(element);
}
}
return result;
}
所以,假设你已经使用了以上可能
Predicate<User> isAuthorized = new Predicate<User>() {
public boolean apply(User user) {
// binds a boolean method in User to a reference
return user.isAuthorized();
}
};
// allUsers is a Collection<User>
Collection<User> authorizedUsers = filter(allUsers, isAuthorized);
public class Predicate {
public static Object predicateParams;
public static <T> Collection<T> filter(Collection<T> target, IPredicate<T> predicate) {
Collection<T> result = new ArrayList<T>();
for (T element : target) {
if (predicate.apply(element)) {
result.add(element);
}
}
return result;
}
public static <T> T select(Collection<T> target, IPredicate<T> predicate) {
T result = null;
for (T element : target) {
if (!predicate.apply(element))
continue;
result = element;
break;
}
return result;
}
public static <T> T select(Collection<T> target, IPredicate<T> predicate, T defaultValue) {
T result = defaultValue;
for (T element : target) {
if (!predicate.apply(element))
continue;
result = element;
break;
}
return result;
}
}
以下示例查找集合之间缺少的对象:
List<MyTypeA> missingObjects = (List<MyTypeA>) Predicate.filter(myCollectionOfA,
new IPredicate<MyTypeA>() {
public boolean apply(MyTypeA objectOfA) {
Predicate.predicateParams = objectOfA.getName();
return Predicate.select(myCollectionB, new IPredicate<MyTypeB>() {
public boolean apply(MyTypeB objectOfB) {
return objectOfB.getName().equals(Predicate.predicateParams.toString());
}
}) == null;
}
});
以下示例在集合中查找实例,并在未找到实例时将集合的第一个元素作为默认值返回:
MyType myObject = Predicate.select(collectionOfMyType, new IPredicate<MyType>() {
public boolean apply(MyType objectOfMyType) {
return objectOfMyType.isDefault();
}}, collectionOfMyType.get(0));
List<Person> olderThan30 =
//Create a Stream from the personList
personList.stream().
//filter the element to select only those with age >= 30
filter(p -> p.age >= 30).
//put those filtered elements into a new List.
collect(Collectors.toList());
In Java 8, You can directly use this filter method and then do that.
List<String> lines = Arrays.asList("java", "pramod", "example");
List<String> result = lines.stream()
.filter(line -> !"pramod".equals(line))
.collect(Collectors.toList());
result.forEach(System.out::println);
public abstract class AbstractFilter<T> {
/**
* Method that returns whether an item is to be included or not.
* @param item an item from the given collection.
* @return true if this item is to be included in the collection, false in case it has to be removed.
*/
protected abstract boolean excludeItem(T item);
public void filter(Collection<T> collection) {
if (CollectionUtils.isNotEmpty(collection)) {
Iterator<T> iterator = collection.iterator();
while (iterator.hasNext()) {
if (excludeItem(iterator.next())) {
iterator.remove();
}
}
}
}
}
Assert.assertEquals(selected, Iterate.select(jdkList, each -> each < 3));
Assert.assertEquals(rejected, Iterate.reject(jdkList, each -> each < 3));
Assert.assertEquals(selected, gscList.select(each -> each < 3));
Assert.assertEquals(rejected, gscList.reject(each -> each < 3));
class LeftDto
{
private int id;
private String text;
public int getId()
{
return id;
}
public int getText()
{
return text;
}
}
class RightDto
{
private int id;
private int leftId;
private String text;
public int getId()
{
return id;
}
public int getLeftId()
{
return leftId;
}
public int getText()
{
return text;
}
}
class JoinedDto
{
private int leftId;
private int rightId;
private String text;
public JoinedDto(int leftId,int rightId,String text)
{
this.leftId = leftId;
this.rightId = rightId;
this.text = text;
}
public int getLeftId()
{
return leftId;
}
public int getRightId()
{
return rightId;
}
public int getText()
{
return text;
}
}
Collection<LeftDto> leftList = new ArrayList<>();
Collection<RightDto> rightList = new ArrayList<>();
27 回答
简单的Java8之前的解决方案:
不幸的是,这个解决方案不是完全通用的,输出列表而不是给定集合的类型 . 此外,引入库或编写包含此代码的函数对我来说似乎有些过分,除非条件很复杂,但是您可以为条件编写函数 .
我会在环中抛出RxJava,这也可以在Android上找到 . RxJava可能并不总是最佳选择,但如果您希望在集合中添加更多转换或在过滤时处理错误,它将为您提供更大的灵活性 .
输出:
有关RxJava的
filter
的更多详细信息,请参见here .假设您正在使用Java 1.5,并且您无法添加Google Collections,我会做一些与Google员工非常相似的事情 . 这是Jon的评论略有不同 .
首先将此接口添加到您的代码库 .
当某个谓词对某种类型成立时,它的实现者可以回答它 . 例如 . 如果
T
User
和AuthorizedUserPredicate<User>
实现了IPredicate<T>
,那么AuthorizedUserPredicate#apply
将返回User
中的传入是否被授权 .然后在一些实用类中,你可以说
所以,假设你已经使用了以上可能
如果关注线性检查的性能,那么我可能希望拥有一个具有目标集合的域对象 . 具有目标集合的域对象将具有用于初始化,添加和设置目标集合的方法的过滤逻辑 .
更新:
在实用程序类(比如谓词)中,我添加了一个select方法,当谓词没有返回预期值时,默认值选项,以及在新IPredicate中使用的params的静态属性 .
以下示例查找集合之间缺少的对象:
以下示例在集合中查找实例,并在未找到实例时将集合的第一个元素作为默认值返回:
更新(在Java 8发布之后):
我(艾伦)第一次发布这个答案已经好几年了,我仍然无法相信我正在为这个答案收集SO分 . 无论如何,现在Java 8已经引入了语言的闭包,我的答案现在会有很大的不同,而且更简单 . 使用Java 8,不需要一个独特的静态实用程序类 . 所以如果你想找到与你的谓词匹配的第一个元素 .
可选项的JDK 8 API具有
get()
,_ 117623,orElse(defaultUser)
,orElseGet(userSupplier)
和orElseThrow(exceptionSupplier)
以及map
,flatMap
和filter
等其他'monadic'函数的功能 .如果您只想收集与谓词匹配的所有用户,请使用
Collectors
终止所需集合中的流 .有关Java 8流如何工作的更多示例,请参见here .
JFilter http://code.google.com/p/jfilter/最适合您的要求 .
JFilter是一个简单而高性能的开源库,用于查询Java bean的集合 .
主要特点
支持集合(java.util.Collection,java.util.Map和Array)属性 .
支持任何深度的集合内的集合 .
支持内部查询 .
支持参数化查询 .
可以在几百毫秒内过滤100万条记录 .
过滤器(查询)以简单的json格式给出,就像Mangodb查询一样 . 以下是一些例子 .
{"id":{"$le":"10"}
其中object id属性小于等于10 .
{"id":{"$in":["0","100"]}}
其中object id属性为0或100 .
{"lineItems":{"lineAmount":"1"}}
其中参数化类型的lineItems集合属性的lineAmount等于1 .
{"$and":[{_ "id":"0"},{"billingAddress":{"city":"DEL"}}]}
其中id属性为0,billingAddress.city属性为DEL .
{"lineItems":{"taxes":{"key":{"code":"GST"},"value":{"$gt":"1.01"}}}}
其中参数化类型的lineItems集合属性具有参数化类型的税映射类型属性,其代码等于GST值大于1.01 .
{'$or':[{_ 'code':'10'},{'skus':{'$and':[{_ 'price':{_ '$in':['20','40']}},{'code':'RedApple'}]}}]}
选择所有产品代码为10或sku价格为20和40且sku代码为"RedApple"的产品 .
使用来自Apache Commons的CollectionUtils.filter(Collection,Predicate) .
一些简单而直接的Java怎么样?
简单,易读且易于使用(适用于Android!)但是,如果您使用的是Java 8,则可以在一行中完成:
请注意,toList()是静态导入的
等待Java 8:
运用
java 8
,特别是lambda expression
,你可以像下面的例子那样做:如果
myProducts
集合中的每个product
,如果prod.price>10
,则将此产品添加到新的筛选列表中 .Google's Guava library中的Collections2.filter(Collection,Predicate)方法可以满足您的需求 .
Java 8(2014)在一行代码中使用流和lambdas解决了这个问题:
这是tutorial .
使用Collection#removeIf来修改集合 . (注意:在这种情况下,谓词将删除满足谓词的对象):
lambdaj允许过滤集合而无需编写循环或内部类:
你能想象更具可读性的东西吗?
Disclaimer: 我是lambdaj的贡献者
自 java 9
Collectors.filtering
启用以来:因此过滤应该是:
例:
设置:
用法:
使用ForEach DSL,您可以编写
给出[The,quick,brown,fox,jumps,over,the,lazy,dog]的集合,这会导致[quick,brown,jumps,over,lazy],即所有字符串超过三个字符 .
ForEach DSL支持的所有迭代样式都是
AllSatisfy
AnySatisfy
Collect
Counnt
CutPieces
Detect
GroupedBy
IndexOf
InjectInto
Reject
Select
有关详细信息,请参阅https://www.iam.unibe.ch/scg/svn_repos/Sources/ForEach
使用Collection Query Engine (CQEngine) . 这是迄今为止最快的方法 .
另见:How do you query object collections in Java (Criteria/SQL-like)?
这里有一些非常好的答案 . 我,我想保持尽可能简单易读:
从Java 8的早期版本开始,您可以尝试以下方法:
例如,如果您有一个整数列表,并且想要过滤大于10的数字然后将这些数字打印到控制台,您可以执行以下操作:
请考虑Google Collections以获取支持泛型的更新集合框架 .
UPDATE :谷歌馆藏库现已弃用 . 您应该使用最新版本的Guava . 它仍然具有集合框架的所有相同扩展,包括基于谓词进行过滤的机制 .
用 Guava :
让我们看一下如何使用Eclipse Collections(以前的GS Collections)过滤内置JDK列表和MutableList .
如果要过滤小于3的数字,您可能会得到以下输出 .
以下是使用匿名内部类作为
Predicate
过滤的方法 .以下是使用Predicates工厂过滤JDK列表和Eclipse Collections MutableLists的一些替代方法 .
这是一个不为谓词分配对象的版本,使用Predicates2工厂而不是
selectWith
方法,该方法需要Predicate2
.有时您想要在负面条件下进行过滤 . Eclipse Collections中有一个名为
reject
的特殊方法 .以下是使用Java 8 lambda作为_177671进行过滤的方法 .
方法
partition
将返回两个集合,其中包含由Predicate
选择和拒绝的元素 .注意:我是Eclipse Collections的提交者 .
这与缺乏真正的闭包相结合,是我对Java最大的抱怨 . 老实说,上面提到的大多数方法都很容易阅读,真正有效;然而,在花费时间与.Net,Erlang等之后......在语言层面集成的列表理解使得一切都变得更加清晰 . 如果没有语言级别的补充,Java就不能像这个领域的许多其他语言一样干净 .
如果性能是一个巨大的问题,谷歌集合是要走的路(或编写自己的简单谓词实用程序) . 对于某些人来说,Lambdaj语法更具可读性,但效率却不高 .
然后有一个我写的图书馆 . 我会忽略任何有关其效率的问题(是的,它那么糟糕)......是的,我知道它基于清晰的反思,并且我不会实际使用它,但它确实有效:
OR
“最佳”方式是一个太宽泛的要求 . 它是“最短的”吗? “最快的”? “读”?过滤到另一个集合?
最简单(但不是最可读)的方法是迭代它并使用Iterator.remove()方法:
现在,为了使其更具可读性,您可以将其包装到实用程序方法中 . 然后发明一个IPredicate接口,创建该接口的匿名实现,并执行以下操作:
其中filterInPlace()迭代集合并调用Predicate.keepIt()以了解要保存在集合中的实例 .
我真的没有理由为这项任务引入第三方库 .
我需要根据列表中已存在的值过滤列表 . 例如,删除小于的所有值当前值 . {2 5 3 4 7 5} - > {2 5 7} . 或者例如删除所有重复项{3 5 4 2 3 5 6} - > {3 5 4 2 6} .
这将像这样使用 .
您确定要过滤Collection本身而不是迭代器吗?
见org.apache.commons.collections.iterators.FilterIterator
或者使用apache commons的第4版org.apache.commons.collections4.iterators.FilterIterator
我写了an extended Iterable class,支持应用功能算法而不复制集合内容 .
用法:
上面的代码实际上会执行
https://code.google.com/p/joquery/
支持不同的可能性,
鉴于收藏,
类型,
Filter
Java 7
Java 8
也,
Sorting (也适用于Java 7)
Grouping (也适用于Java 7)
Joins (也适用于Java 7)
鉴于,
可以加入像,
Expressions
我的答案 Build 在Kevin Wong的基础之上,这里是一个使用
CollectionUtils
从 Spring 天开始的单线程和一个Java 8 lambda表达式 .这与我见过的任何替代方案一样简洁易读(不使用基于方面的库)
Spring CollectionUtils可从Spring版本4.0.2.RELEASE获得,并且记住您需要JDK 1.8和语言级别8 .