使用Google Guava过滤JavaBeans列表
在Java程序中,我有一个我想根据特定属性过滤的bean列表。
例如,假设我有一个Person列表,一个JavaBean,其中Person有许多属性,其中包括’name’。
我还有一个名单。
现在我想找到名字列在名单中的所有人。
使用Google Guava执行此filter的最佳方法是什么?
到目前为止,我已经考虑过将Guava与Apache beanutils结合起来,但这看起来并不优雅。
我还在这里找到了一个reflection扩展库: http : //code.google.com/p/guava-reflection/ ,但我不确定如何使用它(这里有很少的文档)。
有什么想法吗?
ps你能告诉我真的很想念Python列表理解吗?
没有番石榴,这是老式的做法。 (作为番石榴开发者发言。)
List filtered = Lists.newArrayList(); for(Person p : allPersons) { if(acceptedNames.contains(p.getName())) { filtered.add(p); } }
你可以用Guava做到这一点,但Java不是Python,并且试图将它变成Python只会使笨拙且难以理解的代码永久存在。 Guava的function性实用程序应该谨慎使用,并且只有当它们为代码行或性能提供具体且可衡量的好处时才应使用。
Iterable filtered = Iterables.filter(allPersons, new Predicate () { @Override public boolean apply(Person p) { return acceptedNames.contains(p.getName()); } });
如果您的名称列表很大,您最好将其转换为Set(HashSet,首选)并在此集合上调用contains,而不是列表,因为对于HashSet包含O(1),并且O(n)列表。
从句子中解释你的怀疑:
到目前为止,我已经考虑过将Guava与Apache beanutils结合起来,但这看起来并不优雅。
Java虽然如此受欢迎,却缺乏一流的function支持* , Java 8中的变化 ,您将能够做到:
Iterable filtered = filter(allPersons, (Person p) -> acceptedNames.contains(p.getName()));
有了lambdas,它会很优雅。
在此之前,您可以选择:
- 老派的方式(像@Louis写的那样)
- 详细的番石榴filter(@ JB的答案)
- 或其他functionJava库(@ superfav的答案)。
我还想在@ Lois的回答中添加Guava-way创建不可变集合的答案,因为它们比不可修改的更好 ,这也在第15项中描述,最小化 Joshua Bloch的Effective Java中的可变性 ** :
ImmutableList.Builder builder = ImmutableList.builder(); for (final Person p : allPersons) { if (acceptedNames.contains(p.getName())) { builder.add(p); } } ImmutableList filtered = builder.build();
(这是ImmutableList.Builder
在ImmutableList.Builder
创建临时ArrayList
的实现细节)。
*:它让我很烦恼,我来自Python,JavaScript和Perl世界, 其中function得到了更好的处理
**:Guava和Bloch在很多方面紧密耦合 ;)
我对路易斯和JB的回答表示不满。 我不知道番石榴reflection,也许LambdaJ可能是你想要的:
// set up Person me = new Person("Favio"); Person luca = new Person("Luca"); Person biagio = new Person("Biagio"); Person celestino = new Person("Celestino"); Collection meAndMyFriends = asList(me, luca, biagio, celestino); // magic Collection filtered = filter(having(on(Person.class).getName(), isOneOf("Favio", "Luca")), meAndMyFriends); // test assertThat(filtered, hasItems(me, luca)); assertEquals(2, filtered.size());
或者也许你正在寻找Scala,Clojure或Groovy ……
作为番石榴reflection的开发者,我很抱歉我在这么早的阶段就放弃了这个项目(我有一份日常工作,还有一个妻子和孩子:-))。 我的愿景是这样的:
Iterable
现有代码约占60%,所以如果您有兴趣,请与我联系,也许我们可以将它们完成在一起。
如果在单线程应用程序中使用LinkedList
(或任何其他删除操作的集合并不费力),最有效的解决方案是:
final Iterator userIterator = users.iterator(); while (userIterator.hasNext()) { if (/* your condition for exclusion */) { userIterator.remove(); } }
使用Java8样式,您可以使用流+filter来实现您的目标。
persons.stream() .filter(p -> names.contains(p.getName())) .collect(Collectors.toList());
使用Java8,您可以使用Collection.removeIf()
List theList = ...; theList.removeIf( (Person p)->"paul".equals(p.getName()) );
这当然会修改当前列表。
下面是使用guava,beanutils使用generics来使用请求的匹配过滤任何列表的示例
/** * Filter List * * @param inputList * @param requestMatch * @param invokeMethod * @return */ public static Iterable predicateFilterList(List inputList, final String requestMatch, final String invokeMethod) { Predicate filtered = new Predicate () { @Override public boolean apply(T input) { boolean ok = false; try { ok = BeanUtils.getProperty(input, invokeMethod).equalsIgnoreCase(requestMatch); } catch (Exception e) { e.printStackTrace(); } return ok; } }; return Iterables.filter(inputList, filtered); }