如何从Guava不可变排序Multimap中获取tailMap或headMap?
问题背景
Guava中创建排序不可变Multimap的常见方案有两种:
- 允许同key对应重复值:先创建key为树结构的ListMultimap,再转换为不可变Multimap
ListMultimap<Integer, String> mutableMap = MultimapBuilder.treeKeys().arrayListValues().build(); return ImmutableListMultimap.copyOf(mutableMap);
- 同key下值自动去重:使用TreeMultimap构建后转不可变
TreeMultimap<Integer, String> mutableMap = TreeMultimap.create(Ordering.natural(), Ordering.arbitrary()); return ImmutableListMultimap.copyOf(mutableMap);
以上两种方案得到的不可变Multimap,其asMap()返回的是普通ImmutableMap,不支持NavigableMap的tailMap、headMap等按排序规则访问key的方法。
解决方案
Guava目前没有内置同时满足「不可变、key有序、支持导航查询、允许同key重复值」的Multimap实现,可根据业务场景选择以下方案:
- 直接使用
ImmutableSortedMap<Integer, ImmutableList<String>>(推荐)
这是实现需求最简洁稳定的方案,不需要额外封装,天然支持NavigableMap的所有导航操作,示例实现如下:
// 1. 构建可变的有序Map存储数据 SortedMap<Integer, List<String>> mutableSortedMap = new TreeMap<>(); // 2. 写入数据(同key可插入多个重复值) mutableSortedMap.computeIfAbsent(1, k -> new ArrayList<>()).add("a"); mutableSortedMap.computeIfAbsent(1, k -> new ArrayList<>()).add("a"); mutableSortedMap.computeIfAbsent(2, k -> new ArrayList<>()).add("b"); // 3. 转换为不可变的排序Map,值也转换为不可变List ImmutableSortedMap<Integer, ImmutableList<String>> immutableSortedMap = ImmutableSortedMap.copyOfSorted( mutableSortedMap.entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, e -> ImmutableList.copyOf(e.getValue()) )) ); // 4. 直接使用导航查询方法 SortedMap<Integer, ImmutableList<String>> tailMap = immutableSortedMap.tailMap(1); SortedMap<Integer, ImmutableList<String>> headMap = immutableSortedMap.headMap(2);
- 轻量封装同时保留Multimap API
如果需要保留Multimap的put、get等原生操作方法,可以自行封装实现ListMultimap接口,内部持有ImmutableSortedMap<K, ImmutableList<V>>实例,对外额外暴露asNavigableMap()方法返回内部排序Map,即可同时支持Multimap操作和导航查询。 - 值可去重场景直接用
ImmutableSortedSetMultimap
如果业务允许同key下的值自动去重,直接使用Guava内置的ImmutableSortedSetMultimap即可,它的asMap()方法天然返回ImmutableSortedMap,支持所有导航操作:
ImmutableSortedSetMultimap<Integer, String> sortedMultimap = ImmutableSortedSetMultimap.<Integer, String>naturalOrder() .put(1, "a") .put(1, "a") // 重复值会被自动去重 .put(2, "b") .build(); // 直接调用导航方法 SortedMap<Integer, Collection<String>> tailMap = sortedMultimap.asMap().tailMap(1);
内容的提问来源于stack exchange,提问作者brunnsbe
相关产品推荐
相关产品推荐

