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


Answers:


698

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的撰稿人


34
不错,但是静态导入混淆了发生的事情。作为参考,select / having / on是ch.lambdaj.Lambda上的静态导入,大于than是org.hamcrest.Matchers
MikePatel 2012年

11
LambdaJ确实很性感,但值得注意的是,这意味着很大的开销(平均2.6):code.google.com/p/lambdaj/wiki/PerformanceAnalysis
Doc Davluz


7
确实像LamdaJ的示例...类似于.NET内置的Lambda函数。一个人在16岁时可以在哪里喝酒?我们应该考虑添加本地化约束。:P
MAbraham1

3
removeIf示例应为persons.removeIf(p -> p.getAge() <= 16);
vim

223

假设您使用的是Java 1.5,并且无法添加Google Collections,那么我将执行与Google员工非常相似的操作。这与乔恩的评论略有不同。

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

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);

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

更新:

在实用程序类中(假设谓词),我添加了一个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),以及其他“一元”的功能,例如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流如何工作的更多示例,请参见此处


27
是的,但我讨厌重复制造轮子。我宁愿找到一些需要的实用程序库。
Kevin Wong

2
如果您不想使用新系列,这不是最好的方法。使用过滤器迭代器隐喻,它可以输入到新集合中,也可能只是您所需要的。
乔什(Josh)

@Nestor:在Scala理解中,过滤会更加简单:val authorized = for (user <- users if user.isAuthorized) yield user
Alan

这会修改原始收藏还是创建一个全新的收藏?我尝试使用此方法并记录了我的两个集合(原始集合和从该方法返回的集合),它们是相同的。@Alan
Rohan

1
@Rohan,这并不意味着要改变原始集合。请注意,上面的结果集合是新构造的,并且仅当谓词适用时,filter方法才会添加到结果集合中。
艾伦(Alan)

92

使用来自Apache Commons的CollectionUtils.filter(Collection,Predicate)


3
没关系,但这不是通用的,而是就地修改了集合(不好)
Kevin Wong

2
CollectionUtils中还有其他过滤器方法,它们不会修改原始集合。
skaffman 2009年

42
特别是,它的方法没有修改的地方收集org.apache.commons.collections.CollectionUtils#选择(收集,谓语)
艾罗

5
在Commons Collections v4中,现在使用泛型。
贾斯汀·埃默里

1
应谨慎使用此方法,因为它依赖(至少在commons-collections-3.2.1的实现中)依赖于iterator.remove()方法(该方法对于集合是可选的),因此您可能不需要过滤例如数组获取UnsupportedOperationException。
user2417480

67

“最佳”方式要求太高。它是“最短的”吗?“最快的”?“可读”?过滤到位还是进入另一个集合?

最简单(但不是最易读)的方法是对其进行迭代并使用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()以了解实例是否要保留在集合中。

我真的没有理由为此目的引入第三方库。


6
我的投票是这样的:它仅在没有外部库的情况下起作用。与使用for-each语法相比,我从未意识到实例化Iterator实际上可能有用,或者您可以在没有ConcurrentModificationException或类似内容的情况下从列表中删除项目。:)
ZeroOne 2012年

1
我认为这是使用标准Java库而不进行复制的最佳方法。对于1.8,将具有该stream()功能,但并不是每个人都可以使用最新的玩具:P
Populus

这也会修改原始集合吗?@ZeroOne
罗汉

当然可以,@ Rohan。如果您不相信,请尝试一下。;)
ZeroOne 2016年

哈哈,我做到了!但是我想保留我的原始收藏。您能建议一种无需添加外部库的方法吗?@ZeroOne
罗汉

62

考虑将Google Collections用于支持泛型的更新的Collections框架。

更新:谷歌收藏库现已弃用。您应该使用最新版本的Guava。它仍然具有对集合框架的所有相同扩展,包括基于谓词进行过滤的机制。


是的,我知道Google馆藏库。我使用的版本中没有Collections2。我对此问题添加了新的答案,其中列出了特定的方法。
Kevin Wong

7
凯文(Kevin),Iterables.filter()和Iterators.filter()从一开始就在那儿,通常都是您所需要的。
凯文·布瑞里恩

28

等待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());

13
gh ...太冗长了。他们为什么不能这样做:List <Person> result = personList.filter(p-> p.age> 30);
凯文·黄

8
要直接上使用过滤器收集你需要使用removeIf电话:download.java.net/jdk8/docs/api/java/util/...
gavenkoa

6
@KevinWong的“冗长”几乎描述了我认为的整个语言。至少它们是一致的?
Rogue

5
为什么不在最后一部分中使用Collectors.toList()?
Nestor Hernandez Loli 2014年

3
是gentnkoa提供的链接,但未提供404链接personList.removeIf(p -> p.age < 30);。另外,我听说过有关开始实现接受和返回Streams而不是Collections的api的讨论,因为Streams非常有用且快速,但往返于它们的速度很慢。
曼队长

11

从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);

11

我将把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,可以发现在这里


7

设置:

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();
  }
});

2
很好,但是我更喜欢Alan实现,因为您可以获得集合的副本,而不是对其进行更改。而且,Alan的代码是线程安全的,而您的代码不是。
marcospereira

7

一些简单明了的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()是静态导入的



7

让我们看看如何使用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的提交者。


1
您将如何removeIf在列表上或为基元设置?
Vivek Rao

用于removeIf的API已添加到EC 9.1中的原始集合中。eclipse.org/collections/javadoc/9.1.0/org/eclipse/collections/...
唐纳德·拉布

5

使用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


那真是太聪明了!但是,要实现一个漂亮的Ruby式语法,需要做很多工作!不利的是,您的过滤器不是一流的函数,因此无法重复使用。卷上瓶盖……
oxbow_lakes

好点子。重用循环体的一种方法是将循环重构为将选择查询作为参数的方法。但是,到目前为止,这肯定不像真正的闭包那样方便和强大。
阿库恩


5

由于启用了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()));

3

再加上缺乏真正的闭包,这是我对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");

链接?即使您的库效率低下或无法使用,查看源是否可用也会很有趣。
MatrixFrog 2011年

仓库公开(net-machine.com/indefero/p/jdclib/source/tree/master)。您对表达式包感兴趣。测试包中有一个带有示例用法的测试器。我从来没有在上面提到的字符串查询接口上做过很多工作(感觉就像写一个真正的解析器一样),因此测试仪中的显式查询接口是解决之道。
jdc0589 2011年

2

JFilter http://code.google.com/p/jfilter/最适合您的要求。

JFilter是一个简单且高性能的开源库,用于查询Java Bean的集合。

主要特点

  • 支持集合(java.util.Collection,java.util.Map和Array)属性。
  • 支持集合内任何深度的集合。
  • 支持内部查询。
  • 支持参数化查询。
  • 可以在几百毫秒内过滤一百万条记录。
  • 过滤器(查询)以简单的json格式给出,就像Mangodb查询一样。以下是一些示例。
  • {“ id”:{“ $ le”:“ 10”}
    • 其中对象id属性小于等于10。
  • {“ id”:{“ $ in”:[“ 0”,“ 100”]}}
    • 其中对象id属性为0或100。
  • {“ lineItems”:{“ lineAmount”:“ 1”}}
    • 其中参数化类型的lineItems集合属性的lineAmount等于1。
  • {“ $ and”:[{“ id”:“ 0”},{“ billingAddress”:{“ city”:“ DEL”}}]}
    • 其中id属性为0,billingAddress.city属性为DEL。
  • {“ lineItems”:{“ taxes”:{“ key”:{“ code”:“ GST”},“ value”:{“ $ gt”:“ 1.01”}}}}
    • 其中具有参数化类型的税收地图类型属性的参数化类型的lineItems集合属性的代码等于GST值大于1.01。
  • {'$ or':[{'code':'10'},{'skus':{'$ and':[{'price':{'$ in':['20','40']} },{'code':'RedApple'}]}}]}
    • 选择所有产品代码为10或sku价格为20和40且sku代码为“ RedApple”的产品。

1
您应该否认自己是作者(我认为是这样)。
assylias 2012年

是的,我是这个图书馆的作者。
Kamran Ali Khan 2012年

2

我编写了扩展的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);
    }
}


2

这里有一些非常好的答案。我,我想让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();
                }
            }
        }
    }
}

只需为每个过滤器实施适当的excludeItem。您最终将获得完全与单独的筛选器完全一样的集合筛选器
劳伦斯(Lawrence)

1

Java8之前的简单解决方案:

ArrayList<Item> filtered = new ArrayList<Item>(); 
for (Item item : items) if (condition(item)) filtered.add(item);

不幸的是,该解决方案不是完全通用的,它输出列表而不是给定集合的类型。此外,除非条件复杂,否则引入库或编写包装此代码的函数对我来说似乎是过大的,但是您可以为该条件编写函数。


1

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);

1

我的答案基础上,从凯文·黄,这里使用一个班轮CollectionUtils春天和Java 8 拉姆达表达。

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

正如我所见的任何替代方法一样简洁明了(不使用基于方面的库)

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


1

java 8具体来说lambda expression,使用,您可以像下面的示例那样简单地进行操作:

myProducts.stream().filter(prod -> prod.price>10).collect(Collectors.toList())

对于每个product内部myProducts集合,如果为prod.price>10,则将该产品添加到新的过滤列表中。


1

我需要根据列表中已经存在的值来过滤列表。例如,删除所有小于当前值的值。{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;
    }
});

0

用番石榴:

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

0

在Java 8中,您可以直接使用此过滤器方法,然后执行此操作。

 List<String> lines = Arrays.asList("java", "pramod", "example");

 List<String> result = lines.stream()              
         .filter(line -> !"pramod".equals(line))     
         .collect(Collectors.toList());              

 result.forEach(System.out::println); 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.