过滤Java集合的最佳方法是什么?

我想过滤一个基于谓词的java.util.Collection


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的贡献者


假设你使用的是Java 1.5,并且你不能添加Google Collections,那么我会做一些与Google员工非常相似的事情。 Jon的评论略有不同。

首先将此接口添加到您的代码库。

public interface IPredicate<T> { boolean apply(T type); }

它的实现者可以在特定类型的某个谓词是真时回答。 例如,如果TUserAuthorizedUserPredicate<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);

如果关注线性检查的性能,那么我可能想要一个具有目标集合的域对象。 具有目标集合的域对象将具有用于初始化,添加和设置目标集合的方法的过滤逻辑。

更新:

在实用类(比方说谓词)中,当谓词没有返回期望值时,我添加了一个选择方法,其中包含默认值的选项,还有一个静态属性,用于在新的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)第一次发布这个答案已经有好几年了,我仍然不相信我正在为这个答案收集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)以及其他“monadic”函数,如mapflatMapfilter

如果您只想收集与谓词匹配的所有用户,请使用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)。

链接地址: http://www.djcxy.com/p/53879.html

上一篇: What is the best way to filter a Java Collection?

下一篇: Why can't I access the class internals of List<T> when I derive from it?