Java Map,使用values属性过滤

我有一个

TreeMap resMap new TreeMap<String, Map>(); 

我想过滤并保留仅包含已知对的值的条目,让我们说(’mike’=>’jordan’),并避免像下面这样的循环

在我的包含的库apache.commons和google.common中是否有一个过滤方法(可能也会循环,但至少它不那么详细

 for (Entry<String, TreeMap> el : resMap.entrySet()){ if (el.getValue().get("mike").equals("jordan")){ // } } 

您可以使用Guava和Predicate界面中的filter。

 Predicate yourFilter = new Predicate() { public boolean apply(T o) { // your filter } }; 

所以,简单的例子是:

 Predicate evenFilter = new Predicate() { public boolean apply(Integer i) { return (i % 2 == 0); } }; Map map = new HashMap(); Map evenMap = Maps.filterValues(map, evenFilter); 

而不是强制您的客户端代码使用filter/循环,而是在您的类的API中构建您需要的内容:

 public class MyClass { private TreeMap resMap new TreeMap>(); public void filter(String key, String value) { // Some impl here. Either your loop or the guava approach } } 

顺便说一句,如果您使用循环,请考虑更改为:

 for (Iterator>> i = resMap.entrySet().iterator(); i.hasNext();) { Map.Entry> entry = i.next(); if (value.equals(entry.getValue().get(key))) { i.remove(); } } 

循环的变化是:

  • 改变等于的顺序以避免NPE
  • 使用iterator直接删除条目

即使您没有类,也可以轻松地将它包装在实用程序类的静态方法中,在该方法中也可以轻松地对其进行参数化以使用任何嵌套映射:

 public static  void filter(Map> map, K2 key, V value) { // Some impl here } 

这是静态方法的非番石榴impl:

 for (Iterator>> i = map.entrySet().iterator(); i.hasNext();) { Map.Entry> entry = i.next(); if (value.equals(entry.getValue().get(key))) { i.remove(); } } 

看看番石榴的谓词和function 。

这是两个例子。 两者都根据值的属性匹配打印密钥。

 private static void printMatchingEntriesUsingALoop(Map> resMap, String key, String value) { for (Map.Entry> entry : resMap.entrySet()) if (value.equals(entry.getValue().get(key))) System.out.println(entry.getKey()); } private static void printMatchingEntriesUsingGuava(Map> resMap, final String key, final String value) { Predicate> keyValueMatch = new Predicate>() { @Override public boolean apply(@Nullable Map stringStringMap) { return value.equals(stringStringMap.get(key)); } }; Maps.EntryTransformer, Void> printKeys = new Maps.EntryTransformer, Void>() { @Override public Void transformEntry(@Nullable String s, @Nullable Map stringStringMap) { System.out.println(s); return null; } }; Maps.transformEntries(Maps.filterValues(resMap, keyValueMatch), printKeys); } public static void main(String... args) { Map> resMap = new TreeMap>(); printMatchingEntriesUsingALoop(resMap, "first", "mike"); printMatchingEntriesUsingGuava(resMap, "first", "mike"); } 

一个使用循环,一个使用番石榴。

虽然第一个表现更好,但您应该确定哪个是最容易理解和维护的。

来自@missingfaktor的一些建议。 你必须使用自己的判断,但他很好地强调了一些问题。

  1. 很多代码重复。
  2. 特殊情况处理。
  3. 更多圈复杂度。
  4. 由于前三个子弹,更多的错误机会。
  5. 很难遵循代码。

想象一下,您是一名必须支持该软件的新开发人员。 你宁愿面对哪一个?

您可以使用java 8和流过滤地图。 此过程的第一步是使用entrySet().stream()转换为流。 这将为您提供Stream> 。 然后,您可以使用filter(...)来过滤列表。 过滤时,如果输入值应包含在过滤结果中,则应返回true。 过滤结果后,可以使用foreach循环最终结果。

最终结果如下所示:

 resMap.entrySet().stream() .filter(e -> el.getValue().get("mike").equals("jordan")) .foreach(e -> { // Do something with your entry here });