在 Java 7 或更低版本中,HOWTO 使用在地图中找到的 key/value 过滤地图对象列表

In Java 7 or below, HOWTO filter a list of map objects using key/value found in the map

我有一个地图对象列表。这些地图对象有 properties/keys like id, condition_1, condition_2 等。示例地图看起来像这样,

List<Map<String, Object>> allItems = Lists.newArrayList();

Map<String, Object> paramsMap = Maps.newHashMap();

paramsMap.put("id", "a");
paramsMap.put("condition_1", false);
paramsMap.put("condition_2", true);
paramsMap.put("condition_3", false);

allItems.add(paramsMap);

因此,我需要过滤 allItems 对象,使其仅包含具有 condition_1 = truecondition_2 = false 等的地图对象。

我考虑过使用 apache commons CollectionUtils.filter 但这似乎并不能解决我的问题,因为我无法将映射条目指定为过滤条件。

我也不反对使用 Google 番石榴,但我找不到好的解决方案。

基本上,我试图模仿优秀的 JavaScript 库 underscore.js 中的 _.where 功能。

在 Java 8 中你可以使用流:

allItems.stream()
        .filter(map->
        (map.get("condition_1")==true)&&(map.get("condition_2")==false))
        .forEach(System.out::println); //Example output

一个 Guava 解决方案:

Iterables.filter(allItems, new Predicate<Map<String, Object>>() {
   @Override public boolean apply(Map<String, Object> map) {
      return Boolean.TRUE.equals(map.get("condition_1"))
         && Boolean.FALSE.equals(map.get("condition_2"));
   }
});

我认为您将不得不长期这样做。不幸的是 Java 映射不是 Iterable 类型,这意味着大多数常见的库没有针对它们的过滤函数。尝试这样的事情(我相信字符串在 java 中隐式为真,以防您担心您的第一个键值对):

```

boolean result = true;
boolean test = true;
List<Map<String, Object> resultList;
for(Map<String, Object> map : allitems) {
    for(String key : map.keySet()) {
        result = result && test && map.get(key);
        test = !test;
    }
    if(result) { 
        resultList.add(map); 
    }
} 
return resultList;

```

另一种可能性是将您的地图变成 KeyValues 的列表并使用 apache 映射和列表函数。最有可能的是,当您使用 java 7 时,您不会得到那个漂亮的衬垫。希望这对您有所帮助。

我认为最好的解决方案是实际执行与 Kotlin 在方法 Map<K, V>.filter 中所做的相同的操作。

让我们创建谓词:

public interface Predicate<T> {
    boolean apply(T t);
}

Predicate 是一个对 functional-like 编程有用的接口。方法在满足条件时应用 returns true。

然后,像 CollectionUtils 一样创建 class 并在其中放置一个静态方法:

public static <K, V> Map<K, V> filter(
    @NonNull Map<K, V> collection,
    @NonNull Predicate<Map.Entry<K, V>> predicate
) {
    Map<K, V> result = new HashMap<>();
    for (Map.Entry<K, V> entry : collection.entrySet()) {
        if (predicate.apply(entry) {
            result.put(entry.getKey(), entry.getValue();
        }
    }
    return result;
}

这样我们就可以按照以下方式使用这个方法:

Map<String, Object> map = ...;
Map<String, Object> filtered = CollectionUtils.filter(map, new Predicate<Map.Entry<String, Object>>() {
    @Override
    public boolean apply(Map.Entry<String, Object> entry) {
        return isEntryOK(entry);
    }
};

如果你实际上可以使用 Java 8,但由于某些原因你不能使用 Java 的流(例如 Android 开发支持旧版本 Android 与 Java 不兼容 8) 您可以删除语法建议并以更好的形式编写:

Map<String, Object> map = ...;
Map<String, Object> filtered = CollectionUtils.filter(
    map,
    entry -> isEntryOK(entry)
);

或者,我认为最好的解决方案 -> 切换到 Kotlin,它为您提供开箱即用的所有这些功能! :D