Answers:
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的撰稿人
persons.removeIf(p -> p.getAge() <= 16);
假设您使用的是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中使用的参数提供了静态属性。
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流如何工作的更多示例,请参见此处。
val authorized = for (user <- users if user.isAuthorized) yield user
使用来自Apache Commons的CollectionUtils.filter(Collection,Predicate)。
“最佳”方式要求太高。它是“最短的”吗?“最快的”?“可读”?过滤到位还是进入另一个集合?
最简单(但不是最易读)的方法是对其进行迭代并使用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()以了解实例是否要保留在集合中。
我真的没有理由为此目的引入第三方库。
stream()
功能,但并不是每个人都可以使用最新的玩具:P
考虑将Google Collections用于支持泛型的更新的Collections框架。
更新:谷歌收藏库现已弃用。您应该使用最新版本的Guava。它仍然具有对集合框架的所有相同扩展,包括基于谓词进行过滤的机制。
等待Java 8:
List<Person> olderThan30 =
//Create a Stream from the personList
personList.stream().
//filter the element to select only those with age >= 30
filter(p -> p.age >= 30).
//put those filtered elements into a new List.
collect(Collectors.toList());
从Java 8的早期版本开始,您可以尝试执行以下操作:
Collection<T> collection = ...;
Stream<T> stream = collection.stream().filter(...);
例如,如果您有一个整数列表,并且想要过滤> 10的数字,然后将这些数字打印到控制台,则可以执行以下操作:
List<Integer> numbers = Arrays.asList(12, 74, 5, 8, 16);
numbers.stream().filter(n -> n > 10).forEach(System.out::println);
我将把RxJava扔进去,在Android上也可以使用。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的更多细节filter
,可以发现在这里。
设置:
public interface Predicate<T> {
public boolean filter(T t);
}
void filterCollection(Collection<T> col, Predicate<T> predicate) {
for (Iterator i = col.iterator(); i.hasNext();) {
T obj = i.next();
if (predicate.filter(obj)) {
i.remove();
}
}
}
用法:
List<MyObject> myList = ...;
filterCollection(myList, new Predicate<MyObject>() {
public boolean filter(MyObject obj) {
return obj.shouldFilter();
}
});
一些简单明了的Java怎么样
List<Customer> list ...;
List<Customer> newList = new ArrayList<>();
for (Customer c : list){
if (c.getName().equals("dd")) newList.add(c);
}
简单,易读且容易(并且可以在Android中使用!)但是,如果您使用的是Java 8,则只需一行即可:
List<Customer> newList = list.stream().filter(c -> c.getName().equals("dd")).collect(toList());
请注意,toList()是静态导入的
您确定要过滤Collection本身,而不是迭代器吗?
参见org.apache.commons.collections.iterators.FilterIterator
或使用第4版apache commons org.apache.commons.collections4.iterators.FilterIterator
让我们看看如何使用Eclipse Collections过滤内置的JDK List和MutableList。
List<Integer> jdkList = Arrays.asList(1, 2, 3, 4, 5);
MutableList<Integer> ecList = Lists.mutable.with(1, 2, 3, 4, 5);
如果要过滤小于3的数字,则需要以下输出。
List<Integer> selected = Lists.mutable.with(1, 2);
List<Integer> rejected = Lists.mutable.with(3, 4, 5);
这是使用Java 8 lambda作为进行过滤的方法Predicate
。
Assert.assertEquals(selected, Iterate.select(jdkList, each -> each < 3));
Assert.assertEquals(rejected, Iterate.reject(jdkList, each -> each < 3));
Assert.assertEquals(selected, ecList.select(each -> each < 3));
Assert.assertEquals(rejected, ecList.reject(each -> each < 3));
这是使用匿名内部类作为进行过滤的方法Predicate
。
Predicate<Integer> lessThan3 = new Predicate<Integer>()
{
public boolean accept(Integer each)
{
return each < 3;
}
};
Assert.assertEquals(selected, Iterate.select(jdkList, lessThan3));
Assert.assertEquals(selected, ecList.select(lessThan3));
这是使用谓词工厂过滤JDK列表和Eclipse集合 MutableList的一些替代方法。
Assert.assertEquals(selected, Iterate.select(jdkList, Predicates.lessThan(3)));
Assert.assertEquals(selected, ecList.select(Predicates.lessThan(3)));
这是一个不使用谓词分配对象的版本,方法是使用Predicates2工厂,而不是采用的selectWith
方法Predicate2
。
Assert.assertEquals(
selected, ecList.selectWith(Predicates2.<Integer>lessThan(), 3));
有时您想在否定条件下进行过滤。Eclipse Collections中有一个称为的特殊方法reject
。
Assert.assertEquals(rejected, Iterate.reject(jdkList, lessThan3));
Assert.assertEquals(rejected, ecList.reject(lessThan3));
该方法partition
将返回两个集合,其中包含被选中并被拒绝的元素Predicate
。
PartitionIterable<Integer> jdkPartitioned = Iterate.partition(jdkList, lessThan3);
Assert.assertEquals(selected, jdkPartitioned.getSelected());
Assert.assertEquals(rejected, jdkPartitioned.getRejected());
PartitionList<Integer> ecPartitioned = gscList.partition(lessThan3);
Assert.assertEquals(selected, ecPartitioned.getSelected());
Assert.assertEquals(rejected, ecPartitioned.getRejected());
注意:我是Eclipse Collections的提交者。
removeIf
在列表上或为基元设置?
使用ForEach DSL,您可以编写
import static ch.akuhn.util.query.Query.select;
import static ch.akuhn.util.query.Query.$result;
import ch.akuhn.util.query.Select;
Collection<String> collection = ...
for (Select<String> each : select(collection)) {
each.yield = each.value.length() > 3;
}
Collection<String> result = $result();
给定[the,quick,brown,fox,jumps,over,the,lazy,dog]的集合,这将导致[quick,brown,jumps,over,lazy],即所有长度超过三个字符的字符串。
ForEach DSL支持的所有迭代样式为
AllSatisfy
AnySatisfy
Collect
Counnt
CutPieces
Detect
GroupedBy
IndexOf
InjectInto
Reject
Select
有关更多详细信息,请参阅https://www.iam.unibe.ch/scg/svn_repos/Sources/ForEach
由于启用了Java 9 Collectors.filtering
:
public static <T, A, R>
Collector<T, ?, R> filtering(Predicate<? super T> predicate,
Collector<? super T, A, R> downstream)
因此过滤应为:
collection.stream().collect(Collectors.filtering(predicate, collector))
例:
List<Integer> oddNumbers = List.of(1, 19, 15, 10, -10).stream()
.collect(Collectors.filtering(i -> i % 2 == 1, Collectors.toList()));
再加上缺乏真正的闭包,这是我对Java的最大抱怨。老实说,上面提到的大多数方法都非常易于阅读并且非常有效。但是,在花费时间使用.Net,Erlang等之后,在语言级别集成了列表理解功能,因此一切都变得更加整洁。如果在语言级别没有添加,Java就无法像该领域的许多其他语言一样干净。
如果性能是一个非常令人关注的问题,那么Google Collections是最好的选择(或编写您自己的简单谓词实用程序)。Lambdaj语法对于某些人来说更具可读性,但是效率却不如以前。
然后有一个我写的图书馆。我将忽略有关其效率的任何问题(是的,它的劣质)……是的,我知道它基于反射,并且不,我实际上并没有使用它,但是它确实起作用:
LinkedList<Person> list = ......
LinkedList<Person> filtered =
Query.from(list).where(Condition.ensure("age", Op.GTE, 21));
要么
LinkedList<Person> list = ....
LinkedList<Person> filtered = Query.from(list).where("x => x.age >= 21");
JFilter http://code.google.com/p/jfilter/最适合您的要求。
JFilter是一个简单且高性能的开源库,用于查询Java Bean的集合。
主要特点
我编写了扩展的Iterable类,该类支持应用功能算法而无需复制集合内容。
用法:
List<Integer> myList = new ArrayList<Integer>(){ 1, 2, 3, 4, 5 }
Iterable<Integer> filtered = Iterable.wrap(myList).select(new Predicate1<Integer>()
{
public Boolean call(Integer n) throws FunctionalException
{
return n % 2 == 0;
}
})
for( int n : filtered )
{
System.out.println(n);
}
上面的代码将实际执行
for( int n : myList )
{
if( n % 2 == 0 )
{
System.out.println(n);
}
}
使用集合查询引擎(CQEngine)。到目前为止,这是最快的方法。
这里有一些非常好的答案。我,我想让Thins尽可能简单易读:
public abstract class AbstractFilter<T> {
/**
* Method that returns whether an item is to be included or not.
* @param item an item from the given collection.
* @return true if this item is to be included in the collection, false in case it has to be removed.
*/
protected abstract boolean excludeItem(T item);
public void filter(Collection<T> collection) {
if (CollectionUtils.isNotEmpty(collection)) {
Iterator<T> iterator = collection.iterator();
while (iterator.hasNext()) {
if (excludeItem(iterator.next())) {
iterator.remove();
}
}
}
}
}
https://code.google.com/p/joquery/
支持各种可能性,
给定集合,
Collection<Dto> testList = new ArrayList<>();
类型的
class Dto
{
private int id;
private String text;
public int getId()
{
return id;
}
public int getText()
{
return text;
}
}
过滤
Java 7
Filter<Dto> query = CQ.<Dto>filter(testList)
.where()
.property("id").eq().value(1);
Collection<Dto> filtered = query.list();
Java 8
Filter<Dto> query = CQ.<Dto>filter(testList)
.where()
.property(Dto::getId)
.eq().value(1);
Collection<Dto> filtered = query.list();
也,
Filter<Dto> query = CQ.<Dto>filter()
.from(testList)
.where()
.property(Dto::getId).between().value(1).value(2)
.and()
.property(Dto::grtText).in().value(new string[]{"a","b"});
排序(也适用于Java 7)
Filter<Dto> query = CQ.<Dto>filter(testList)
.orderBy()
.property(Dto::getId)
.property(Dto::getName)
Collection<Dto> sorted = query.list();
分组(也可用于Java 7)
GroupQuery<Integer,Dto> query = CQ.<Dto,Dto>query(testList)
.group()
.groupBy(Dto::getId)
Collection<Grouping<Integer,Dto>> grouped = query.list();
联接(也可用于Java 7)
鉴于
class LeftDto
{
private int id;
private String text;
public int getId()
{
return id;
}
public int getText()
{
return text;
}
}
class RightDto
{
private int id;
private int leftId;
private String text;
public int getId()
{
return id;
}
public int getLeftId()
{
return leftId;
}
public int getText()
{
return text;
}
}
class JoinedDto
{
private int leftId;
private int rightId;
private String text;
public JoinedDto(int leftId,int rightId,String text)
{
this.leftId = leftId;
this.rightId = rightId;
this.text = text;
}
public int getLeftId()
{
return leftId;
}
public int getRightId()
{
return rightId;
}
public int getText()
{
return text;
}
}
Collection<LeftDto> leftList = new ArrayList<>();
Collection<RightDto> rightList = new ArrayList<>();
可以像这样加入
Collection<JoinedDto> results = CQ.<LeftDto, LeftDto>query().from(leftList)
.<RightDto, JoinedDto>innerJoin(CQ.<RightDto, RightDto>query().from(rightList))
.on(LeftFyo::getId, RightDto::getLeftId)
.transformDirect(selection -> new JoinedDto(selection.getLeft().getText()
, selection.getLeft().getId()
, selection.getRight().getId())
)
.list();
表达方式
Filter<Dto> query = CQ.<Dto>filter()
.from(testList)
.where()
.exec(s -> s.getId() + 1).eq().value(2);
我的答案基础上,从凯文·黄,这里使用一个班轮CollectionUtils
从春天和Java 8 拉姆达表达。
CollectionUtils.filter(list, p -> ((Person) p).getAge() > 16);
正如我所见的任何替代方法一样简洁明了(不使用基于方面的库)
Spring CollectionUtils可从4.0.2.RELEASE的春季版本获得,请记住您需要JDK 1.8和语言级别8+。
我需要根据列表中已经存在的值来过滤列表。例如,删除所有小于当前值的值。{2 5 3 4 7 5}-> {2 5 7}。或者例如删除所有重复项{3 5 4 2 3 5 6}-> {3 5 4 2 6}。
public class Filter {
public static <T> void List(List<T> list, Chooser<T> chooser) {
List<Integer> toBeRemoved = new ArrayList<>();
leftloop:
for (int right = 1; right < list.size(); ++right) {
for (int left = 0; left < right; ++left) {
if (toBeRemoved.contains(left)) {
continue;
}
Keep keep = chooser.choose(list.get(left), list.get(right));
switch (keep) {
case LEFT:
toBeRemoved.add(right);
continue leftloop;
case RIGHT:
toBeRemoved.add(left);
break;
case NONE:
toBeRemoved.add(left);
toBeRemoved.add(right);
continue leftloop;
}
}
}
Collections.sort(toBeRemoved, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2 - o1;
}
});
for (int i : toBeRemoved) {
if (i >= 0 && i < list.size()) {
list.remove(i);
}
}
}
public static <T> void List(List<T> list, Keeper<T> keeper) {
Iterator<T> iterator = list.iterator();
while (iterator.hasNext()) {
if (!keeper.keep(iterator.next())) {
iterator.remove();
}
}
}
public interface Keeper<E> {
boolean keep(E obj);
}
public interface Chooser<E> {
Keep choose(E left, E right);
}
public enum Keep {
LEFT, RIGHT, BOTH, NONE;
}
}
这将像这样使用蜜蜂。
List<String> names = new ArrayList<>();
names.add("Anders");
names.add("Stefan");
names.add("Anders");
Filter.List(names, new Filter.Chooser<String>() {
@Override
public Filter.Keep choose(String left, String right) {
return left.equals(right) ? Filter.Keep.LEFT : Filter.Keep.BOTH;
}
});
用番石榴:
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