如何过滤Java集合(基于谓词)?
我想根据谓词过滤一个。java.util.Collection
Java 8(2014)在一行代码中使用流和lambda解决了这个问题:
List<Person> beerDrinkers = persons.stream()
.filter(p -> p.getAge() > 16).collect(Collectors.toList());
这是一个教程。
使用集合#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); }
它的实现者可以回答某个谓词在特定类型为真时。例如,如果 was 和 实现 ,则返回传入的是否经过授权。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 内使用的参数。
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 发布之后):
自从我(艾伦)第一次发布这个答案以来已经好几年了,我仍然不敢相信我正在为这个答案收集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 能够执行 、、和 ,以及其他“monadic”函数,例如 、 和 。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 流如何工作的更多示例,请参阅此处。