【问题标题】:How to filter a Java Collection (based on predicate)?如何过滤 Java 集合(基于谓词)?
【发布时间】:2010-09-12 10:25:43
【问题描述】:

我想根据谓词过滤java.util.Collection

【问题讨论】:

    标签: java collections filter


    【解决方案1】:

    Java 8 (2014) 在一行代码中使用流和 lambdas 解决了这个问题:

    List<Person> beerDrinkers = persons.stream()
        .filter(p -> p.getAge() > 16).collect(Collectors.toList());
    

    这是tutorial

    使用Collection#removeIf 就地修改集合。 (注意:在这种情况下,谓词将删除满足谓词的对象):

    persons.removeIf(p -> p.getAge() <= 16);
    

    lambdaj 允许过滤集合而无需编写循环或内部类:

    List<Person> beerDrinkers = select(persons, having(on(Person.class).getAge(),
        greaterThan(16)));
    

    你能想象出更易读的东西吗?

    免责声明:我是 lambdaj 的贡献者

    【讨论】:

    • 不错,但静态导入混淆了正在发生的事情。作为参考,select/have/on 是 ch.lambdaj.Lambda 上的静态导入,greaterThan 是 org.hamcrest.Matchers
    • LambdaJ 确实很性感,但值得注意的是它意味着显着的开销(平均 2.6):code.google.com/p/lambdaj/wiki/PerformanceAnalysis
    • 真的很喜欢这个LamdaJ的例子……类似于.NET内置的Lambda函数。一个人在 16 岁时可以在哪里喝酒?我们应该考虑添加本地化约束。 :P
    • removeIf 示例应为 persons.removeIf(p -&gt; p.getAge() &lt;= 16);
    【解决方案2】:

    假设您使用的是Java 1.5,并且您不能添加Google Collections,我会做一些与谷歌人所做的非常相似的事情。这与 Jon 的 cmets 略有不同。

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

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

    当某个谓词对某种类型为真时,它的实现者可以做出回答。例如。如果TUserAuthorizedUserPredicate&lt;User&gt;实现IPredicate&lt;T&gt;,则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 中使用的 params 的静态属性.

    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),以及其他“一元”函数,例如 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 流如何工作的更多示例,请参阅 here

    【讨论】:

    • 是的,但我讨厌重复地重新发明轮子。我宁愿找到一些可以在我需要时使用的实用程序库。
    • 如果您不想要新系列,这不是最好的方法。使用过滤器迭代器隐喻,它可以输入到一个新的集合中,或者它可能就是你所需要的。
    • @Nestor:在 Scala 理解中,过滤会简单得多:val authorized = for (user &lt;- users if user.isAuthorized) yield user
    • 这是修改原始收藏还是创建一个全新的收藏?我尝试使用此方法并记录了我的两个集合(原始集合和从该方法返回的集合),它们是相同的。 @艾伦
    • @Rohan,这并不是要改变原始集合。请注意,上面的结果集合是新建的,只有当谓词适用时,过滤器方法才会添加到结果集合中。
    【解决方案3】:

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

    【讨论】:

    • 这个没问题,但它不是通用的,并且会在适当的位置修改集合(不好)
    • CollectionUtils中还有其他过滤方法不修改原始集合。
    • 特别地,就地修改集合的方法是 org.apache.commons.collections.CollectionUtils#select(Collection,Predicate)
    • 在 Commons Collections v4 中,现在使用泛型。
    • 这个方法应该谨慎使用,因为它依赖于(至少在commons-collections-3.2.1的实现中)对集合是可选的iterator.remove()方法,而不是过滤,比如说一个数组,你可能会得到一个 UnsupportedOperationException。
    【解决方案4】:

    “最佳”方式的要求太宽泛了。它是“最短的”吗? “最快的”? “可读”? 就地过滤还是过滤到另一个集合中?

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

    我真的认为没有理由为这项任务引入第三方库。

    【讨论】:

    • 我投票赞成这个:它可以正常工作,没有外部库。与使用 for-each 语法相比,我从未意识到实例化 Iterator 实际上是有用的,或者您可以在没有 ConcurrentModificationException 或类似的东西的情况下从列表中删除项目。 :)
    • 我认为这是使用标准 Java 库而不进行复制的最佳方式。对于 1.8,会有 stream() 功能,但不是每个人都可以玩最新的玩具:P
    • 这是否也修改了原始集合? @ZeroOne
    • 是的,当然可以,@Rohan。不信就试试。 ;)
    • 哈哈,我做到了!但我想保留我原来的收藏。你能建议一种不添加外部库的方法吗? @ZeroOne
    【解决方案5】:

    请考虑 Google Collections 以获得支持泛型的更新集合框架。

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

    【讨论】:

    • 是的,我知道 Google 收藏库。我使用的版本没有 Collections2。我为这个问题添加了一个新的答案,列出了具体的方法。
    • Kevin、Iterables.filter() 和 Iterators.filter() 从一开始就存在,通常是你所需要的。
    【解决方案6】:

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

    【讨论】:

    • 呃……太冗长了。他们为什么不能这样做: List result = personList.filter(p -> p.age > 30);
    • 要直接在 Collection 上使用过滤器,您需要使用 removeIf 调用:download.java.net/jdk8/docs/api/java/util/…
    • @KevinWong "verbose" 几乎描述了我认为的整个语言。至少它们是一致的?
    • 为什么不在最后一部分使用 Collectors.toList()?
    • Here 是一个给出的链接,它不是 404。personList.removeIf(p -&gt; p.age &lt; 30); 不那么冗长。另外,我听说过开始实施接受和返回 Streams 而不是 Collections 的 API,因为 Streams 非常有用且快速,但往返它们很慢。
    【解决方案7】:

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

    【讨论】:

      【解决方案8】:

      我会把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 的细节可以在 here 找到。

      【讨论】:

        【解决方案9】:

        设置:

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

        【讨论】:

        • 很好,但我更喜欢 Alan 实现,因为您可以获得集合的副本而不是更改它。此外,Alan 的代码是线程安全的,而您的则不是。
        【解决方案10】:

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

        【讨论】:

          【解决方案11】:

          您确定要过滤集合本身而不是迭代器吗?

          org.apache.commons.collections.iterators.FilterIterator

          或使用第 4 版 apache commons org.apache.commons.collections4.iterators.FilterIterator

          【讨论】:

            【解决方案12】:

            让我们看看如何使用Eclipse Collections过滤内置的JDK列表和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));
            

            这里有一些使用 Predicates 工厂过滤 JDK 列表和 Eclipse Collections MutableLists 的替代方法。

            Assert.assertEquals(selected, Iterate.select(jdkList, Predicates.lessThan(3)));
            Assert.assertEquals(selected, ecList.select(Predicates.lessThan(3)));
            

            这是一个不为谓词分配对象的版本,通过使用Predicates2 工厂而不是采用Predicate2selectWith 方法。

            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 的提交者。

            【讨论】:

            【解决方案13】:

            使用 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-ish 语法需要做很多工作!不利的是,您的过滤器不是一流的功能,因此无法重复使用。滚动关闭...
            • 好点。重用循环体的一种方法是将循环重构为将选择查询作为参数的方法。然而,这肯定不如真正的闭包那么方便和强大。
            【解决方案14】:

            Google's Guava library 中的 Collections2.filter(Collection,Predicate) 方法可以满足您的需求。

            【讨论】:

              【解决方案15】:

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

              【讨论】:

                【解决方案16】:

                再加上缺乏真正的闭包,这是我对 Java 最大的不满。 老实说,上面提到的大多数方法都很容易阅读并且非常有效。然而,在花时间使用 .Net、Erlang 等之后......在语言级别集成的列表理解使一切变得更加清晰。如果没有语言级别的添加,Java 就无法像该领域的许多其他语言一样干净。

                如果性能是一个非常重要的问题,Google 集合是要走的路(或编写您自己的简单谓词实用程序)。 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");
                

                【讨论】:

                • 链接?即使您的库效率低下或无法使用,查看源是否可用也会很有趣。
                • 公开存储库 (net-machine.com/indefero/p/jdclib/source/tree/master)。您对表达式包感兴趣。测试包有一个带有示例用法的测试器。我从来没有真正在上面提到的字符串查询接口上做过很多工作(感觉不像写一个真正的解析器),所以测试器中的显式查询接口是要走的路。
                【解决方案17】:

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

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

                主要特点

                • 支持集合(java.util.Collection、java.util.Map 和 Array)属性。
                • 支持任意深度的集合内集合。
                • 支持内部查询。
                • 支持参数化查询。
                • 可以在 100 毫秒内过滤 100 万条记录。
                • 过滤器(查询)以简单的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 参数化类型的集合属性具有参数化类型的税收地图类型属性的代码等于大于 1.01 的 GST 值。
                • {'$or':[{'code':'10'},{'skus': {'$and':[{'price':{'$in':['20', '40 ']}}, {'code':'RedApple'}]}}]}
                  • 选择产品代码为 10 或 sku 价格为 20 和 40 且 sku 代码为“RedApple”的所有产品。

                【讨论】:

                • 你应该否认你是作者(我认为是这样)。
                • 是的,我是这个库的作者。
                【解决方案18】:

                我写了an extended Iterable class,支持在不复制集合内容的情况下应用函数算法。

                用法:

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

                【讨论】:

                  【解决方案19】:

                  【讨论】:

                    【解决方案20】:

                    使用java 8,特别是lambda expression,您可以像下面的示例一样简单地做到这一点:

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

                    myProducts 集合中每个product 的位置,如果是prod.price&gt;10,则将此产品添加到新的过滤列表中。

                    【讨论】:

                      【解决方案21】:

                      这里有一些非常棒的答案。我,我希望尽可能保持简单易读:

                      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 即可。您最终将拥有单独的过滤器,就像您在 Collections 上拥有排序器一样......
                      【解决方案22】:

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

                      【讨论】:

                        【解决方案23】:

                        简单的 pre-Java8 解决方案:

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

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

                        【讨论】:

                          【解决方案24】:

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

                          【讨论】:

                            【解决方案25】:

                            我的回答基于 Kevin Wong 的回答,这里是使用 spring 中的 CollectionUtils 和 Java 8 lambda 表达式的单行代码。

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

                            这与我见过的任何替代方案一样简洁易读(不使用基于方面的库)

                            Spring CollectionUtils 可从 spring 版本 4.0.2.RELEASE 开始使用,记住您需要 JDK 1.8 和语言级别 8+。

                            【讨论】:

                              【解决方案26】:

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

                              【讨论】:

                                【解决方案27】:

                                就我而言,我正在寻找排除特定字段 null 的列表。 这可以通过 for 循环来完成,并填充没有空地址的对象的临时列表。 但感谢 Java 8 Streams

                                List<Person> personsList = persons.stream()
                                .filter(p -> p.getAdrress() != null).collect(Collectors.toList());
                                

                                #java #collection #collections #java8 #streams

                                【讨论】:

                                  【解决方案28】:

                                  使用番石榴:

                                  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
                                  

                                  【讨论】:

                                    【解决方案29】:

                                    Java 集合流的替代(更轻量级)替代方案是 Ocl.java 库,它使用原始集合和 lambda:https://github.com/eclipse/agileuml/blob/master/Ocl.java

                                    例如,一个简单的过滤器和对 ArrayList 单词的求和 可能是:

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

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

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

                                    【讨论】:

                                      猜你喜欢
                                      • 1970-01-01
                                      • 2014-10-26
                                      • 2021-04-13
                                      • 1970-01-01
                                      • 2019-03-17
                                      • 2020-05-20
                                      • 1970-01-01
                                      • 1970-01-01
                                      相关资源
                                      最近更新 更多