我想根据谓词过滤java.util.Collection
。
发布于 2008-09-23 16:41:41
假设你正在使用Java 1.5,并且你不能添加Google Collections,我会做一些非常类似于谷歌人所做的事情。这是Jon评论的一个细微的变化。
首先,将此接口添加到代码库中。
public interface IPredicate<T> { boolean apply(T type); }
它的实现者可以回答当某个谓词对某个类型为真时。例如,如果T
为User
,并且AuthorizedUserPredicate<User>
实现了IPredicate<T>
,则AuthorizedUserPredicate#apply
将返回传入的User
是否经过授权。
然后在某个实用程序类中,您可以这样说
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);
如果线性检查的性能令人担忧,那么我可能希望拥有一个具有目标集合的域对象。具有目标集合的域对象将具有用于初始化、添加和设置目标集合的方法的过滤逻辑。
更新:
在实用程序类(假设是Predicate)中,我添加了一个select方法,该方法在谓词未返回预期值时具有默认值选项,还添加了一个用于在新IPredicate中使用的参数的静态属性。
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));
更新(在Java 8发布之后):
自从我(Alan)第一次发布这个答案已经有好几年了,我仍然不敢相信我为这个答案收集了这么多积分。无论如何,既然Java 8已经在该语言中引入了闭包,我的回答将会有很大的不同,并且更加简单。在Java 8中,不需要不同的静态实用程序类。所以如果你想找到与你的谓词匹配的第一个元素。
final UserService userService = ... // perhaps injected IoC
final Optional<UserModel> userOption = userCollection.stream().filter(u -> {
boolean isAuthorized = userService.isAuthorized(u);
return isAuthorized;
}).findFirst();
用于可选选项的JDK8API具有get()
、isPresent()
、orElse(defaultUser)
、orElseGet(userSupplier)
和orElseThrow(exceptionSupplier)
的能力,以及其他“一元”函数,如map
、flatMap
和filter
。
如果您想简单地收集与谓词匹配的所有用户,那么可以使用Collectors
来终止所需集合中的流。
final UserService userService = ... // perhaps injected IoC
final List<UserModel> userOption = userCollection.stream().filter(u -> {
boolean isAuthorized = userService.isAuthorized(u);
return isAuthorized;
}).collect(Collectors.toList());
有关Java8 streams如何工作的更多示例,请参阅here。
发布于 2008-09-23 16:28:44
使用Apache Commons中的CollectionUtils.filter(Collection,Predicate)。
发布于 2008-09-23 16:41:33
“最好的”方式太宽泛了。它是“最短的”吗?“最快”?“可读性”?原地过滤还是放到另一个集合中?
最简单(但不是最具可读性)的方法是迭代它并使用Iterator.remove()方法:
Iterator<Foo> it = col.iterator();
while( it.hasNext() ) {
Foo foo = it.next();
if( !condition(foo) ) it.remove();
}
现在,为了使其更具可读性,您可以将其包装到一个实用方法中。然后发明一个IPredicate接口,创建该接口的匿名实现,并执行以下操作:
CollectionUtils.filterInPlace(col,
new IPredicate<Foo>(){
public boolean keepIt(Foo foo) {
return foo.isBar();
}
});
其中filterInPlace()迭代集合并调用Predicate.keepIt()来了解实例是否要保留在集合中。
我真的看不到只为这项任务引入第三方库的理由。
https://stackoverflow.com/questions/122105
复制相似问题