如何高效拆分含Multimap的Java Map中的真假条目
高效拆分Map<String, Multimap<Boolean, String>>为两个目标Map的方案
要高效完成拆分,核心是一次遍历原集合避免重复迭代,同时利用Guava Multimap的视图特性减少不必要的数据拷贝。以下是Java 8及以下版本的两种实现方式,分别适用于不同场景:
一、传统循环实现(最高效,一次遍历)
这种方式仅遍历原Map一次,同时填充两个目标Map,适合对性能要求极高的场景。可根据需求选择直接使用视图(无拷贝)或创建独立集合(拷贝数据):
1. 使用视图(无拷贝,性能最优)
如果不需要修改拆分后的Multimap,且能接受原集合修改会影响目标集合的情况,直接用Guava的Multimaps.filterKeys生成视图:
import com.google.common.collect.*; public class MultimapSplitter { public static void split(Map<String, Multimap<Boolean, String>> originalMap, Map<String, Multimap<Boolean, String>> trueEntriesMap, Map<String, Multimap<Boolean, String>> falseEntriesMap) { // 清空目标Map,避免原有数据干扰 trueEntriesMap.clear(); falseEntriesMap.clear(); // 一次遍历原Map,同时处理true和false条目 for (Map.Entry<String, Multimap<Boolean, String>> entry : originalMap.entrySet()) { String outerKey = entry.getKey(); Multimap<Boolean, String> innerMultimap = entry.getValue(); // 生成仅包含true条目的视图Multimap Multimap<Boolean, String> trueSubmap = Multimaps.filterKeys(innerMultimap, Boolean::booleanValue); if (!trueSubmap.isEmpty()) { trueEntriesMap.put(outerKey, trueSubmap); } // 生成仅包含false条目的视图Multimap Multimap<Boolean, String> falseSubmap = Multimaps.filterKeys(innerMultimap, f -> !f); if (!falseSubmap.isEmpty()) { falseEntriesMap.put(outerKey, falseSubmap); } } } // 使用示例 public static void main(String[] args) { Map<String, Multimap<Boolean, String>> original = Maps.newHashMap(); Multimap<Boolean, String> mm1 = ArrayListMultimap.create(); mm1.put(true, "a"); mm1.put(true, "b"); mm1.put(false, "c"); original.put("key1", mm1); Multimap<Boolean, String> mm2 = ArrayListMultimap.create(); mm2.put(false, "d"); original.put("key2", mm2); Map<String, Multimap<Boolean, String>> trueMap = Maps.newHashMapWithExpectedSize(original.size()); Map<String, Multimap<Boolean, String>> falseMap = Maps.newHashMapWithExpectedSize(original.size()); split(original, trueMap, falseMap); } }
2. 创建独立集合(拷贝数据,与原集合解耦)
如果需要拆分后的集合独立于原集合(修改原集合不影响目标集合),则将视图拷贝为新的Multimap实现:
将上述代码中的视图创建部分替换为:
// 拷贝true条目到新的ArrayListMultimap Multimap<Boolean, String> trueSubmap = ArrayListMultimap.create(Multimaps.filterKeys(innerMultimap, Boolean::booleanValue));
二、Java 8 Stream实现(代码简洁,需两次遍历)
如果对性能要求稍低,追求代码简洁,可以使用Stream API,缺点是会遍历原Map两次:
import com.google.common.collect.*; import java.util.Map; import java.util.stream.Collectors; public class StreamMultimapSplitter { public static void main(String[] args) { Map<String, Multimap<Boolean, String>> original = Maps.newHashMap(); // 初始化原集合... // 构建仅包含true条目的Map Map<String, Multimap<Boolean, String>> trueMap = original.entrySet().stream() .filter(entry -> !entry.getValue().get(true).isEmpty()) .collect(Collectors.toMap( Map.Entry::getKey, entry -> ArrayListMultimap.create(Multimaps.filterKeys(entry.getValue(), Boolean::booleanValue)) )); // 构建仅包含false条目的Map Map<String, Multimap<Boolean, String>> falseMap = original.entrySet().stream() .filter(entry -> !entry.getValue().get(false).isEmpty()) .collect(Collectors.toMap( Map.Entry::getKey, entry -> ArrayListMultimap.create(Multimaps.filterKeys(entry.getValue(), f -> !f)) )); } }
性能优化关键点
- 一次遍历优先:传统循环方式仅遍历原集合一次,避免Stream方式两次遍历的额外开销
- 利用视图减少拷贝:Guava的
filterKeys返回的是视图,无需复制数据,性能最优;仅在需要解耦时才进行拷贝 - 初始化指定预期大小:使用
Maps.newHashMapWithExpectedSize(original.size())初始化目标Map,避免HashMap扩容带来的性能损耗
内容的提问来源于stack exchange,提问作者Timothy Clotworthy
相关产品推荐
相关产品推荐

