我有一个
TreeMap resMap new TreeMap<String, Map<String, String>>();
我想过滤,只保留条目值包含已知对,比方说(“迈克” =>“乔丹”),并避免象下面这样一个循环
有没有在我的图书馆包括和apache.commons一个google.common滤波方法(也可能会做一个循环太多,但至少它是更简洁
for (Entry<String, TreeMap<String, String>> el : resMap.entrySet()){
if (el.getValue().get("mike").equals("jordan")){
//
}
}
您可以使用番石榴和过滤器Predicate
接口。
Predicate<T> yourFilter = new Predicate<T>() {
public boolean apply(T o) {
// your filter
}
};
因此,简单的例子是:
Predicate<Integer> evenFilter = new Predicate<Integer>() {
public boolean apply(Integer i) {
return (i % 2 == 0);
}
};
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Map<Integer, Integer> evenMap = Maps.filterValues(map, evenFilter);
而不是强迫你的客户端代码使用过滤器/循环,建立你需要为你的类的API是什么:
public class MyClass {
private TreeMap resMap new TreeMap<String, Map<String, String>>();
public void filter(String key, String value) {
// Some impl here. Either your loop or the guava approach
}
}
顺便说一句,如果你使用你的循环,考虑改变这样的:
for (Iterator<Map.Entry<String, TreeMap<String, String>>> i = resMap.entrySet().iterator(); i.hasNext();) {
Map.Entry<String, TreeMap<String, String>> entry = i.next();
if (value.equals(entry.getValue().get(key))) {
i.remove();
}
}
到循环的变化是:
- 平等的更改,以避免NPE
- 使用
iterator
直接允许移除项
即使你没有一个类,你可以很容易地包起来的一个实用工具类,它也很容易被参数与任何嵌套地图工作的静态方法:
public static <K1, K2, V> void filter(Map<K1, Map<K2, V>> map, K2 key, V value) {
// Some impl here
}
下面是静态方法非番石榴IMPL:
for (Iterator<Map.Entry<K1, Map<K2, V>>> i = map.entrySet().iterator(); i.hasNext();) {
Map.Entry<K1, Map<K2, V>> entry = i.next();
if (value.equals(entry.getValue().get(key))) {
i.remove();
}
}
这里有两个例子。 根据比赛的价值属性中的打印两者的关键。
private static void printMatchingEntriesUsingALoop(Map<String, Map<String, String>> resMap, String key, String value) {
for (Map.Entry<String, Map<String, String>> entry : resMap.entrySet())
if (value.equals(entry.getValue().get(key)))
System.out.println(entry.getKey());
}
private static void printMatchingEntriesUsingGuava(Map<String, Map<String, String>> resMap, final String key, final String value) {
Predicate<Map<String, String>> keyValueMatch =
new Predicate<Map<String, String>>() {
@Override
public boolean apply(@Nullable Map<String, String> stringStringMap) {
return value.equals(stringStringMap.get(key));
}
};
Maps.EntryTransformer<String, Map<String, String>, Void> printKeys =
new Maps.EntryTransformer<String, Map<String, String>, Void>() {
@Override
public Void transformEntry(@Nullable String s,
@Nullable Map<String, String> stringStringMap) {
System.out.println(s);
return null;
}
};
Maps.transformEntries(Maps.filterValues(resMap, keyValueMatch), printKeys);
}
public static void main(String... args) {
Map<String, Map<String, String>> resMap = new TreeMap<String, Map<String, String>>();
printMatchingEntriesUsingALoop(resMap, "first", "mike");
printMatchingEntriesUsingGuava(resMap, "first", "mike");
}
一个使用一个循环,一个用番石榴。
虽然第一个执行得更好,你应该决定,这将是最容易理解和维护。
从@missingfaktor一些建议。 你必须使用你自己的判断,但他强调了一些的问题很好。
- 很多重复的代码。
- 特殊情况的处理。
- 更多的圈复杂度。
- 错误的更多的机会,因为前三个子弹的结果。
- 很难跟随代码。
想象一下,你是新开发谁得支持该软件。 你更愿意面对?
您可以使用Java 8和流过滤地图。 在这个过程的第一步是转换成使用流entrySet().stream()
这给你一个Stream<Map.Entry<String, TreeMap<String, String>>
。 然后,您可以使用filter(...)
过滤列表。 当您筛选,你应该当输入值应包括在过滤后的结果返回true。 当您筛选的结果,你可以在最后的结果用的foreach循环。
最终的结果将如下所示:
resMap.entrySet().stream()
.filter(e -> el.getValue().get("mike").equals("jordan"))
.foreach(e -> {
// Do something with your entry here
});