Guava记录 - 新集合类型Multimap

一、简介

Multimap是一种将键与任意多个值相关联的通用方法。
官网对其的描述如下:

Every experienced Java programmer has, at one point or another, implemented a Map<K, List<V>> or Map<K, Set<V>>, and dealt with the awkwardness of that structure. For example, Map<K, Set<V>> is a typical way to represent an unlabeled directed graph. Guava's Multimap framework makes it easy to handle a mapping from keys to multiple values. A Multimap is a general way to associate keys with arbitrarily many values.

大致意思为:咱每个有经验的程序员都基本都实现过Map<K, List<V>> 或者Map<K, Set<V>>并处理对应业务.但是这种结构很笨拙.而Guava的Multimap会使得操作这种映射关系更容易.

有两种方法可以从概念上理解多Multimap

1、一个key对应一个值:

a -> 1
a -> 2
a -> 4
b -> 3
c -> 5

2、一个key对应一个集合

a -> [1, 2, 4]
b -> [3]
c -> [5]

通常情况下来说最好是使用第一种方式,但是也可以通过asMap的方式返回一个Map<K, List<V>> .
最重要的是,这里不会存在一个key映射到一个空集合.
在Multimap中一个key要么至少有一个值,要么就不存在.
但是我们很少直接使用Multimap接口,更多的是使用ListMultimap或者Setultimap接口,它们分别把键映射到list或者set上.

二、如何构建Multimap?

官网给的最直接的创建例子如下:它允许你如何配置表表示对应的key和value.

    // creates a ListMultimap with tree keys and array list values
    ListMultimap<String, Integer> treeListMultimap =
    MultimapBuilder.treeKeys().arrayListValues().build();

    // creates a SetMultimap with hash keys and enum set values
    SetMultimap<Integer, MyEnum> hashEnumMultimap =
    MultimapBuilder.hashKeys().enumSetValues(MyEnum.class).build();

也可以使用create()的方式进行创建,但是是不鼓励这样做的.部分Multimap对象创建如下:

        //通过create方式创建.但是官方是不鼓励的

        //通过create方式 - 创建ArrayListMultimap对象
        Multimap<String, String> multimap = ArrayListMultimap.create();
        
        //通过create方式 - 创建HashMultimap对象
        Multimap<String, String> hashMultimap = HashMultimap.create();
        
        //通过create方式 - 创建LinkedHashMultimap对象
        Multimap<String, String> linkedHashMultimap = LinkedHashMultimap.create();
        
        //通过create方式 - 创建LinkedListMultimap对象
        Multimap<String, String> linkedListMultimap = LinkedListMultimap.create();
        
        //通过create方式 - 创建TreeMultimap对象
        Multimap<String, String> treeMultimap = TreeMultimap.create();
        
        //创建ImmutableListMultimap对象
        Multimap<String, String> immutableListMultimap = ImmutableListMultimap.of();
        
        //通过create方式 - 创建TreeMultimap对象
        Multimap<String, String> immutableSetMultimap = ImmutableSetMultimap.of();

三、常用方法

1、修改类型的方法 - Modifying
a、put(K, V)方法

添加一个k - v 映射
put(K, V)等价于multimap.get(key).add(value).

实验代码:

        ListMultimap<String, Integer> treeListMultimap =
                MultimapBuilder.treeKeys().arrayListValues().build();
        treeListMultimap.put("ListA", 1);
        treeListMultimap.put("ListA", 2);
        treeListMultimap.put("ListA", 3);
        //以上的put方式等价于 - xxxxMap.get().add()方式
        treeListMultimap.get("ListB").add(4);

        System.out.println("==================ListMultimap=====gasMap方法值====" + treeListMultimap.asMap());

        输出:==================ListMultimap=====get方法值===={ListA=[1, 2, 3], ListB=[4]}
b、putAll(k, Iterable<V>)方法

批量添加k - v数据,等同于Iterables.addAll(multimap.get(key), values)

实验代码:

        //test put all - 等价于Iterables.addAll
        treeListMultimap.putAll("ListC", dataList);
        //等价于put all
        Iterables.addAll(treeListMultimap.get("ListC"), dataList);
        System.out.println("==================ListMultimap=====gasMap方法值====" + treeListMultimap.asMap());

        输出:==================ListMultimap=====get方法值===={ListA=[1, 2, 3], ListB=[4], ListC=[2001, 2002, 2003, 2001, 2002, 2003]}
c、remove(k, v)方法

从键到值删除一个关联,如果multimap改变则返回true。
等价于multimap.get(key).remove(value).
removeAll的缩小版本.

实验代码:

        treeListMultimap.remove("ListA",1);
        System.out.println("==================ListMultimap==remove之后===get方法值====" + treeListMultimap.get("ListA"));

        输出:==================ListMultimap==remove之后===get方法值====[2, 3]
d、removeAll(K)方法

删除并返回与指定键关联的所有值。返回的集合可以修改,也可以不修改,但是修改它不会影响multimap
实验代码:

        treeListMultimap.removeAll("ListA");
        System.out.println("==================ListMultimap==removeAll之后===get方法值====" + treeListMultimap.get("ListA"));
        
        输出:==================ListMultimap==removeAll之后===get方法值====[]
e、replaceValues(k, Iterable<V>)方法

清除与键关联的所有值,并设置与每个值关联的键。返回以前与键关联的值。

实验代码:

        treeListMultimap.replaceValues("ListsB",Lists.newArrayList(101,201));
        System.out.println("==================ListMultimap==replaceValues之后===get方法值====" + treeListMultimap.get("ListsB"));

        输出:  ==================ListMultimap==replaceValues之后===get方法值====[101, 201]
2、查询类型的方法 - Views
a、asMap()方法

将Multimap视图以map的视图形式返回.
返回的试图支持修改,但是不支持put()以及putAll()方法.

实验的代码:

        Map<String, Collection<Integer>> testAsMap = treeListMultimap.asMap();
        testAsMap.remove("ListA");
        System.out.println("==================测试asMap======remove方法后========="+testAsMap);

        //测试put
        testAsMap.put("ListD", Lists.newArrayList(301));
        //测试putAll
        testAsMap.putAll(Maps.newHashMap());

实验结果:

==================测试asMap======remove方法后========={ListB=[4], ListC=[2001, 2002, 2003, 2001, 2002, 2003], ListsB=[101, 201]}
java.lang.UnsupportedOperationException
    at java.util.AbstractMap.put(AbstractMap.java:209)
    at com.toxic.anepoch.guava.parsing.collection.newtypes.TestMultimap.main(TestMultimap.java:60)
b、entries()方法

返回当前multiMap的映射关系.

实验代码:

        System.out.println("==============测试MultiMap的entries()方法=============="+treeListMultimap.entries());
        输出:==============测试MultiMap的entries()方法==============[ListB=4, ListC=2001, ListC=2002, ListC=2003, ListC=2001, ListC=2002, ListC=2003, ListsB=101, ListsB=201]
c、keySet()

返回当前MultiMap的key - set集合

实验代码:

        System.out.println("==============测试MultiMap的keySet()方法=============="+treeListMultimap.keySet());
        输出:==============测试MultiMap的keySet()方法==============[ListB, ListC, ListsB]
d、keys()

返回当前MultiMap的MultiSet视图

实验代码:

        System.out.println("==============测试MultiMap的keys()方法=============="+treeListMultimap.keys());
        输出:==============测试MultiMap的keys()方法==============[ListB, ListC x 6, ListsB x 2]
e、values()

返回当前MultiMap拍平了的value - collection集合

实验代码:

        System.out.println("==============测试MultiMap的values()方法=============="+treeListMultimap.values());
        输出:==============测试MultiMap的values()方法==============[4, 2001, 2002, 2003, 2001, 2002, 2003, 101, 201]

四、最后值得注意的是MultiMap并不是一个map

感兴趣的可以了解一下
官网描述:

A Multimap<K, V> is not a Map<K, Collection<V>>, though such a map might be used in a Multimap implementation. Notable differences include:

  • Multimap.get(key) always returns a non-null, possibly empty collection. This doesn't imply that the multimap spends any memory associated with the key, but instead, the returned collection is a view that allows you to add associations with the key if you like.
  • If you prefer the more Map-like behavior of returning null for keys that aren't in the multimap, use the asMap() view to get a Map<K, Collection<V>>. (Or, to get a Map<K,List<V>> from a ListMultimap, use the static Multimaps.asMap() method. Similar methods exist for SetMultimap and SortedSetMultimap.)
  • Multimap.containsKey(key) is true if and only if there are any elements associated with the specified key. In particular, if a key k was previously associated with one or more values which have since been removed from the multimap, Multimap.containsKey(k) will return false.
  • Multimap.entries() returns all entries for all keys in the Multimap. If you want all key-collection entries, use asMap().entrySet().
  • Multimap.size() returns the number of entries in the entire multimap, not the number of distinct keys. Use Multimap.keySet().size() instead to get the number of distinct keys.

......未完待续

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。