Java 8( 2014 )在一行代码中使用流和 lambda 解决了此问题:
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 的撰稿人
假设您使用的是Java 1.5 ,并且无法添加Google Collections ,那么我将执行与 Google 员工非常相似的操作。这与乔恩的评论略有不同。
首先将此接口添加到您的代码库中。
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);
如果需要关注线性检查的性能,那么我可能想要一个具有目标集合的域对象。具有目标集合的域对象将具有用于初始化,添加和设置目标集合的方法的过滤逻辑。
更新:
在实用工具类中(假设谓词),我添加了一个 select 方法,当谓词未返回期望值时,该选项带有默认值选项,并且还为要在新 IPredicate 中使用的 params 设置了静态属性。
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));
UPDATE(在 Java 8 版本之后):
自从我(Alan)首次发布此答案以来已经有好几年了,但我仍然不敢相信我正在为此答案收集 SO 点。无论如何,既然 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();
可选的 JDK 8 API 具有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());
有关 Java 8 流如何工作的更多示例,请参见此处。
使用来自 Apache Commons 的CollectionUtils.filter(Collection,Predicate)。