我想根据谓词筛选java.util.Collection。


当前回答

使用集合查询引擎(CQEngine)。这是目前为止最快的方法。

请参见:如何在Java中查询对象集合(Criteria/SQL-like)?

其他回答

我的回答建立在Kevin Wong的基础上,这里是一个使用spring中的CollectionUtils和Java 8 lambda表达式的一行程序。

CollectionUtils.filter(list, p -> ((Person) p).getAge() > 16);

这是我见过的最简洁易读的方法(不使用基于方面的库)。

Spring CollectionUtils可从Spring版本4.0.2获得。请记住,您需要JDK 1.8和语言级别8+。

我将把RxJava加入其中,它在Android上也可用。RxJava可能并不总是最好的选择,但如果您希望在集合上添加更多转换或在过滤时处理错误,RxJava将为您提供更大的灵活性。

Observable.from(Arrays.asList(1, 2, 3, 4, 5))
    .filter(new Func1<Integer, Boolean>() {
        public Boolean call(Integer i) {
            return i % 2 != 0;
        }
    })
    .subscribe(new Action1<Integer>() {
        public void call(Integer i) {
            System.out.println(i);
        }
    });

输出:

1
3
5

更多关于RxJava过滤器的细节可以在这里找到。

Java集合流的一个替代(更轻量级的)选择是Ocl.java库,它使用vanilla集合和lambdas: https://github.com/eclipse/agileuml/blob/master/Ocl.java

例如,对数组列表中的单词进行简单的筛选和求和 可能是:

ArrayList<Word> sel = Ocl.selectSequence(words, 
                             w -> w.pos.equals("NN")); 
int total = Ocl.sumint(Ocl.collectSequence(sel,
                             w -> w.text.length())); 

Where Word有字符串pos;字符串文本;属性。效率似乎与流选项相似,例如,在两个版本中,10000个单词在大约50毫秒内处理。

Python、Swift等都有等效的OCL库。基本上,Java集合流重新发明了OCL操作——>select, ->collect等,这些操作自1998年以来就存在于OCL中。

番石榴:

Collection<Integer> collection = Lists.newArrayList(1, 2, 3, 4, 5);

Iterators.removeIf(collection.iterator(), new Predicate<Integer>() {
    @Override
    public boolean apply(Integer i) {
        return i % 2 == 0;
    }
});

System.out.println(collection); // Prints 1, 3, 5

假设您使用的是Java 1.5,并且不能添加谷歌集合,我将做一些非常类似于谷歌人员所做的事情。这与乔恩的评论略有不同。

首先将该接口添加到代码库中。

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发布后):

自从我(艾伦)第一次发布这个答案已经有好几年了,我仍然不敢相信我的这个答案能获得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。

如果您只想收集与谓词匹配的所有用户,那么使用collector终止所需集合中的流。

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流如何工作的更多示例,请参见这里。