Guava——New Collection Types

Guava introduces a number of new collection types that are not in the JDK, but that we have found to be broadly useful. These are all designed to coexist happily with the JDK collections framework, without shoehorning things into the JDK collection abstractions.

All

Multiset
SortedMultiset
Multimap
ListMultimap
SetMultimap
BiMap
ClassToInstanceMap
Table

Multiset

troditional

Map<String, Integer> counts = new HashMap<String, Integer>();
for (String word : words) {
  Integer count = counts.get(word);
  if (count == null) {
    counts.put(word, 1);
  } else {
    counts.put(word, count + 1);
  }
}

guava

// List 允许重复,有顺序
        // Set 不允许重复、无顺序
        // MultiSet 允许重复,不保证顺序
        String strWorld="wer|dfd|dd|dfd|dda|de|dr";
        String[] words = strWorld.split("\\|");
        Multiset<String> multiset = HashMultiset.create();
        for (String word : words) {
            multiset.add(word);
        }

        for(String key:multiset.elementSet()){
            System.out.println(key+" count:"+multiset.count(key));
        }

notice

Guava provides a new collection type, Multiset, which supports adding multiples of elements. Wikipedia defines a multiset, in mathematics, as “a generalization of the notion of set in which members are allowed to appear more than once...In multisets, as in sets and in contrast to tuples, the order of elements is irrelevant: The multisets {a, a, b} and {a, b, a} are equal.”

There are two main ways of looking at this:

  • This is like an ArrayList<E> without an ordering constraint: ordering does not matter.
  • This is like a Map<E, Integer>, with elements and counts.

methods

Multiset接口定义的接口主要有:
    add(E element) :向其中添加单个元素
    add(E element,int occurrences) : 向其中添加指定个数的元素
    count(Object element) : 返回给定参数元素的个数
    remove(E element) : 移除一个元素,其count值 会响应减少
    remove(E element,int occurrences): 移除相应个数的元素
    elementSet() : 将不同的元素放入一个Set中
    entrySet(): 类似与Map.entrySet 返回Set<Multiset.Entry>。包含的Entry支持使用getElement()和getCount()
    setCount(E element ,int count): 设定某一个元素的重复次数
    setCount(E element,int oldCount,int newCount): 将符合原有重复个数的元素修改为新的重复次数
    retainAll(Collection c) : 保留出现在给定集合参数的所有的元素
    removeAll(Collectionc) : 去除出现给给定集合参数的所有的元素

Implementations

Multimap

implemented a Map<K, List<V>> or Map<K, Set<V>>,using multimap will be easy.
You rarely use the Multimap interface directly, however; more often you'll use ListMultimap or SetMultimap, which map keys to a List or a Set respectively.

Construction

// 可创建1 key : n value 的map结构
// 可创建1 key : n value 的map结构
        Multimap<String, Integer> multimap = ArrayListMultimap.create();
        for (int i = 0; i < 2; i++) {
            multimap.put("aa", i);
            multimap.put("bb", i);
        }
        // 所有value的数量
        System.out.println("multimap.size() = " + multimap.size());
        System.out.println("multimap.keys() = " + multimap.keys());
        // key不存在 会得到空集合,而不是null
        List<Integer> valueList = (List<Integer>) multimap.get("key");
        System.out.println("valueList = " + valueList);

        valueList = (List<Integer>) multimap.get("aa");
        System.out.println("valueList = " + valueList);

        // 转为map
        Map<String, Collection<Integer>> map = multimap.asMap();
        List<Integer> list2 = (List<Integer>)map.get("key");
        // key 不存在,得到null
        System.out.println("list2 = " + list2);

        valueList = (List<Integer>) map.get("aa");
        System.out.println("valueList = " + valueList);

        Collection<Map.Entry<String, Integer>> entries = multimap.entries();
        System.out.println("entries = " + entries);

View

Multimap也支持一系列强大的视图功能:
  1.asMap把自身Multimap<K, V>映射成Map<K, Collection<V>>视图。这个Map视图支持remove和修改操作,但是不支持put和putAll。严格地来讲,当你希望传入参数是不存在的key,而且你希望返回的是null而不是一个空的可修改的集合的时候就可以调用asMap().get(key)。(你可以强制转型asMap().get(key)的结果类型-对SetMultimap的结果转成Set,对ListMultimap的结果转成List型-但是直接把ListMultimap转成Map<K, List<V>>是不行的。)
  2.entries视图是把Multimap里所有的键值对以Collection<Map.Entry<K, V>>的形式展现。
  3.keySet视图是把Multimap的键集合作为视图
  4.keys视图返回的是个Multiset,这个Multiset是以不重复的键对应的个数作为视图。这个Multiset可以通过支持移除操作而不是添加操作来修改Multimap。
  5.values()视图能把Multimap里的所有值“平展”成一个Collection<V>。这个操作和Iterables.concat(multimap.asMap().values())很相似,只是它返回的是一个完整的Collection。

尽管Multimap的实现用到了Map,但Multimap<K, V>不是Map<K, Collection<V>>。因为两者有明显区别:
  1.Multimap.get(key)一定返回一个非null的集合。但这不表示Multimap使用了内存来关联这些键,相反,返回的集合只是个允许添加元素的视图。
  2.如果你喜欢像Map那样当不存在键的时候要返回null,而不是Multimap那样返回空集合的话,可以用asMap()返回的视图来得到Map<K, Collection<V>>。(这种情况下,你得把返回的Collection<V>强转型为List或Set)。
  3.Multimap.containsKey(key)只有在这个键存在的时候才返回true。
  4.Multimap.entries()返回的是Multimap所有的键值对。但是如果需要key-collection的键值对,那就得用asMap().entries()。
  5.Multimap.size()返回的是entries的数量,而不是不重复键的数量。如果要得到不重复键的数目就得用Multimap.keySet().size()。

Implements

Implementation Keys 的行为类似 Values的行为类似
ArrayListMultimap HashMap ArrayList
HashMultimap HashMap HashSet
LinkedListMultimap LinkedHashMap* LinkedList*
LinkedHashMultimap LinkedHashMap LinkedHashSet
TreeMultimap TreeMap TreeSet
ImmutableListMultimap ImmutableMap ImmutableList
ImmutableSetMultimap ImmutableMap ImmutableSet

Multimap提供了丰富的实现,所以你可以用它来替代程序里的Map<K, Collection<V>>,具体的实现如下:

Implementation Keys 的行为类似 Values的行为类似
ArrayListMultimap HashMap ArrayList
HashMultimap HashMap HashSet
LinkedListMultimap LinkedHashMap* LinkedList*
LinkedHashMultimap LinkedHashMap LinkedHashSet
TreeMultimap TreeMap TreeSet
ImmutableListMultimap ImmutableMap ImmutableList
ImmutableSetMultimap ImmutableMap ImmutableSet

以上这些实现,除了immutable的实现都支持null的键和值。

  1. LinkedListMultimap.entries()能维持迭代时的顺序。
  2. LinkedHashMultimap维持插入的顺序,以及键的插入顺序。
    要注意并不是所有的实现都正真实现了Map<K, Collection<V>>!(尤其是有些Multimap的实现为了最小话开销,使用了自定义的hash table)

BiMap

troditional

Map<String, Integer> nameToId = Maps.newHashMap();
Map<Integer, String> idToName = Maps.newHashMap();

nameToId.put("Bob", 42);
idToName.put(42, "Bob");
// what happens if "Bob" or 42 are already present?
// weird bugs can arise if we forget to keep these in sync...

A BiMap<K, V> is a Map<K, V> that

  • allows you to view the "inverse" BiMap<V, K> with inverse()
  • ensures that values are unique, making values() a Set
HashBiMap<String, Integer> hashBiMap = HashBiMap.create();
        hashBiMap.put("a1", 1);
        hashBiMap.put("a2", 2);
        hashBiMap.put("a3", 3);
        System.out.println("hashBiMap = " + hashBiMap);

        BiMap<Integer, String> inverse = hashBiMap.inverse();
        System.out.println("inverse = " + inverse);

        // BiMap 强制保持 1:1 关系,如果要在已有value上添加另外的key,则会抛出异常
        // 要覆盖已有value对应的entry,则可以putforce
        hashBiMap.forcePut("a4", 3);
        System.out.println("hashBiMap = " + hashBiMap);
  • BiMap.put(key, value) will throw an IllegalArgumentException if you attempt to map a key to an already-present value. If you wish to delete any preexisting entry with the specified value, use BiMap.forcePut(key, value) instead.
  • inverse方法会返回一个反转的BiMap,但是注意这个反转的map不是新的map对象,它实现了一种视图关联,这样你对于反转后的map的所有操作都会影响原先的map对象。

Note: BiMap utilities like synchronizedBiMap live in Maps.

Table

        Table<Integer, Integer, String> table = HashBasedTable.create();
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                table.put(i, j, i + "-" + j);
            }
        }
        System.out.println("table = " + table);
        Map<Integer, String> row0 = table.row(0);
        System.out.println("row 0 = " + row0);
        
        Map<Integer, String> colum0 = table.column(0);
        System.out.println("table.column(0) = " + colum0);
        
        Map<Integer, Map<Integer, String>> rowMap = table.rowMap();
        System.out.println("rowMap.get(0).get(0) = " + rowMap.get(0).get(0));

        Map<Integer, Map<Integer, String>> columnMap = table.columnMap();
        System.out.println("columnMap.get(0).get(0) = " + columnMap.get(0).get(0));

Implements

Table有以下实现:
  HashBasedTable:基于HashMap<R, HashMap<C, V>>的实现。
  TreeBasedTable:基于TreeMap<R, TreeMap<C, V>>的实现。
  ImmutableTable:基于ImmutableMap<R, ImmutableMap<C, V>>的实现。(注意,ImmutableTable已对稀疏和密集集合做了优化)
  ArrayTable:ArrayTable是一个需要在构建的时候就需要定下行列的表格。这种表格由二维数组实现,这样可以在密集数据的表格的场合,提高时间和空间的效率。

ClassToInstanceMap

RangeSet

A RangeSet describes a set of disconnected, nonempty ranges. When adding a range to a mutable RangeSet, any connected ranges are merged together, and empty ranges are ignored. For example:

// range.closed [],即闭区间 ,range.closeOpen [),即右开区间
        RangeSet<Integer> rangeSet = TreeRangeSet.create();
        rangeSet.add(Range.closed(5,10));
        System.out.println("rangeSet:"+rangeSet);
        rangeSet.add(Range.closedOpen(12, 15));
        System.out.println("rangeSet:"+rangeSet);
        // 会合并
        rangeSet.add(Range.closedOpen(11, 13));
        System.out.println("rangeSet:"+rangeSet);

        // 会分割
        rangeSet.remove(Range.open(7,8));
        System.out.println("rangeSet:"+rangeSet);

RangeMap

RangeMap is a collection type describing a mapping from disjoint, nonempty ranges to values. Unlike RangeSet, RangeMap never "coalesces" adjacent mappings, even if adjacent ranges are mapped to the same values. For example:

// 不会像rangeSet自动合并区间
        RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
        rangeMap.put(Range.closed(1, 5), "1-5");
        System.out.println(rangeMap.get(2));

        rangeMap.remove(Range.open(2,3));
        System.out.println(rangeMap);
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,444评论 4 365
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,867评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,157评论 0 248
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,312评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,673评论 3 289
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,802评论 1 223
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,010评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,743评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,470评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,696评论 2 250
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,187评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,538评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,188评论 3 240
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,127评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,902评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,889评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,741评论 2 274

推荐阅读更多精彩内容

  • 不可变集合类 为什么要使用不可变集合不可变对象有很多优点,包括: 当对象被不可信的库调用时,不可变形式是安全的;不...
    icecrea阅读 1,571评论 0 0
  • 这个不错分享给大家,从扣上看到的,就转过来了 《电脑专业英语》 file [fail] n. 文件;v. 保存文...
    麦子先生R阅读 6,515评论 5 24
  • 身处闹市的自己仿佛唯有自己浑身长满刺才能不被伤害,最后却发现自己早已千疮百孔。于是开始学着慢慢的拔刺,开始学着收敛...
    小仲夏阅读 324评论 0 0
  • 今年《奇葩说》已经来到了第四个年头,理论上一个产品的生命周期为5年,《奇葩说》能一直保持较高关注度和原创团队有分不...
    爱吐槽的南瓜汪阅读 332评论 0 2
  • 周末清理日,主要是衣柜整理。最喜欢在午饭后做,边消化边收拾整齐了。 搭档出门了,闲下来静心看完想看的短篇。晚上的粉...
    周湘泉阅读 117评论 0 2