百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

Guava HashMultimap使用及注意事项

toyiye 2024-08-25 15:39 4 浏览 0 评论

Guava HashMultimap使用及注意事项[1]

hello,各位大佬上午|中午|下午|晚上|凌晨好,我是一灰灰,今天给大家介绍一个相对基础的知识点 HashMultmap;

guava基本上可以说是java开发项目中,大概率会引入的包,今天介绍的主角是一个特殊的容器 -- HashMultmap,可以简单的将它的数据结构理解为Map<K, Set<V>>

那么为什么会突然想到介绍一下它呢,因为昨天刚因为对它理解不够深刻,把它当作了Map<K, List<V>>来使用,结果出了问题;既然如此那就好好盘一盘,反思一下

1. 数据模型介绍

正常来讲,在使用一个新的数据对象时,我们应该先了解它的数据模型;

直接看源码,会发现实际存储数据的结构为 Map<K, Collection<V>>

abstract class AbstractMapBasedMultimap<K, V> extends AbstractMultimap<K, V> implements Serializable {
    private transient Map<K, Collection<V>> map;
}

再jdk中Map也有很多实现,那么具体是哪个呢?

从构造方法出发,来看下这个map成员的初始化过程

private HashMultimap(int expectedKeys, int expectedValuesPerKey) {
    super(Platform.newHashMapWithExpectedSize(expectedKeys));
    this.expectedValuesPerKey = 2;
    Preconditions.checkArgument(expectedValuesPerKey >= 0);
    this.expectedValuesPerKey = expectedValuesPerKey;
}


private HashMultimap(Multimap<? extends K, ? extends V> multimap) {
    super(Platform.newHashMapWithExpectedSize(multimap.keySet().size()));
    this.expectedValuesPerKey = 2;
    this.putAll(multimap);
}

关键点就在 Platform.newHashMapWithExpectedSize,熟悉的小伙伴已经能很快给出答案了,这个map就是我们常用的HashMap

接下来需要关注的就是value中的Collection,是什么容器类型了;对于它,则从添加元素的时候来定位put(key, value)

关键源码如下

public boolean put(@Nullable K key, @Nullable V value) {
    Collection<V> collection = (Collection)this.map.get(key);
    if (collection == null) {
        collection = this.createCollection(key);
        if (collection.add(value)) {
            ++this.totalSize;
            this.map.put(key, collection);
            return true;
        } else {
            throw new AssertionError("New Collection violated the Collection spec");
        }
    } else if (collection.add(value)) {
        ++this.totalSize;
        return true;
    } else {
        return false;
    }
}

这个写法相信大家都不会陌生,存在时,直接添加到容器;不存在时,则可以通过 createCollection来创建容器,并塞入Map;其具体的实现逻辑如下

// com.google.common.collect.HashMultimap#createCollection
Set<V> createCollection() {
    return Platform.newHashSetWithExpectedSize(this.expectedValuesPerKey);
}

所以HashMultimap的底层数据存储就是我们的老朋友 HashMap<K, HashSet<V>>

2. 简单使用介绍

基本来讲,HashMultimap的使用姿势非常简单了,下面给出简单实例演示一下,基本上看看就会了

2.1 容器创建

// 创建一个默认的 HashMap<String, Set<Integer>>,容器的初始化容量与HashMap的默认值一样
HashMultimap<String, Integer> map = HashMultimap.create();


// 当我们知道容器的个数时,推荐使用下面这种方式, 
// HashMap 设置容量为8, 每个HashSet的容量初始化为16
HashMultimap<String, Integer> map2 = HashMultimap.create(8, 16);


// 另外一个就是基于MultMap来创建的case了
HashMultimap<String, Integer> map3 = HashMultimap.create(map);

注意上面的第三种实现,需要理解的是 map3.get(key) != map.get(key)

即基于原来的容器初始化的新容器,其value是一个新的容器对象,将之前的value中所有元素,都塞入新的容器中,并不是直接引用就的容器对象(这么一说是不是更想是深拷贝,而不是浅拷贝呢?)

2.2 添加元素

// 添加单个元素
map.put("hello", 510);




// 添加多个元素
map.putAll("skill", Arrays.asList(1, 2, 3, 4, 1));

注意

?因为value是HashSet,所以重复的元素会忽略?塞入重复的元素会忽略?再次申明,添加重复的元素会忽略

(没错,我就是这里出了问题......)

2.3 移除元素

// 移除skill对应的集合中,value=3的元素
map.remove("skill", 3);


// 移除key
map.removeAll("hello");

2.4 替换元素

如果我们希望将整个value都换成一个新的集合,那么可以使用replaceValue

// 直接替换skill对应的value集合,新的值为 {100, 200, 300}
map.replaceValues("skill", Arrays.asList(100, 200, 300));

2.5 获取元素及遍历

// 获取对应的value集合,当不存在时,返回空集合(不是null,简直是贴心)
Set<Integer> set = map.get("skill");

foreach方式的迭代

for (Map.Entry<String, Integer> entry: map.entries()) {
    System.out.println(entry.getKey() + ":" + entry.getValue());
}

注意上面的迭代成员 Map.Entry<String, Integer>,其key依然是HashMap的key,而value则是这个集合中的没一个元素,比如容器中的值为("skill": [100,200,300])时,此时输出如下

skill:200
skill:100
skill:300

2.6 输出所有的key

// 输出所有的key,
map.keys()


// 输出key集合
map.keySet();

他们两有啥区别?看个实例

HashMultimap<String, Integer> map = HashMultimap.create();
map.replaceValues("skill", Arrays.asList(100, 200, 300));
System.out.println("keys=" + map.keys());
System.out.println("keySet=" + map.keySet());

输出如下

keys=[skill x 3]
keySet=[skill]

上面这个skill x 3是什么鬼,实际上表示skill有三个,返回的容器可以理解为List,不去重

而下面的KeySet()则返回的是个Set,会去重

2.7 输出所有的value

map.values()

通过上面的再理解这个就简单了,所有的value都合并再一个List,接下来我们看一下两种遍历方式

HashMultimap<String, Integer> map = HashMultimap.create();
map.putAll("skill", Arrays.asList(100, 200, 300));
map.put("a", 100);


for (Integer v: map.values()) {
    System.out.println(v);
}

实际输出如下

100
100
200
300

3. 小结

这里主要介绍的是Gauva的容器HashMultimap的数据模型及使用姿势,知识点相对来说比较基础,再实际使用的时候,请牢记,把它看作是简单方便易使用的 HashMap<K, HashSet<V>> 即可,重点注意value中的元素不能重复即可

那么当我们希望value是个List时,可以怎么整呢?

?此时可以使用 LinkedMultiValueMap 来替代,它的底层数据结构实际上就是 HashMap<K, LinkedHashMap<V>>

?使用 ArrayListMultimap 也可以,底层数据结构为 HashMap<K, ArrayList<V>>

最后提一句,guava的这几个容器的实现,其源码阅读起来不会吃力,且设计思路也非常典型,比如如果让我们自己来基于jdk的基础容器实现一个类似的容器,如何优雅的去实现呢? 这里就给了一个标准答案,强烈推荐有兴趣的小伙伴瞅一下

一灰灰的联系方式

尽信书则不如无书,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

?个人站点:https://blog.hhui.top

References

[1] Guava HashMultimap使用及注意事项: https://blog.hhui.top/
[2] 小灰灰Blog:
https://weibo.com/p/1005052169825577/home

相关推荐

# Python 3 # Python 3字典Dictionary(1)

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中,格式如...

Python第八课:数据类型中的字典及其函数与方法

Python3字典字典是另一种可变容器模型,且可存储任意类型对象。字典的每个键值...

Python中字典详解(python 中字典)

字典是Python中使用键进行索引的重要数据结构。它们是无序的项序列(键值对),这意味着顺序不被保留。键是不可变的。与列表一样,字典的值可以保存异构数据,即整数、浮点、字符串、NaN、布尔值、列表、数...

Python3.9又更新了:dict内置新功能,正式版十月见面

机器之心报道参与:一鸣、JaminPython3.8的热乎劲还没过去,Python就又双叒叕要更新了。近日,3.9版本的第四个alpha版已经开源。从文档中,我们可以看到官方透露的对dic...

Python3 基本数据类型详解(python三种基本数据类型)

文章来源:加米谷大数据Python中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建。在Python中,变量就是变量,它没有类型,我们所说的"类型"是变...

一文掌握Python的字典(python字典用法大全)

字典是Python中最强大、最灵活的内置数据结构之一。它们允许存储键值对,从而实现高效的数据检索、操作和组织。本文深入探讨了字典,涵盖了它们的创建、操作和高级用法,以帮助中级Python开发...

超级完整|Python字典详解(python字典的方法或操作)

一、字典概述01字典的格式Python字典是一种可变容器模型,且可存储任意类型对象,如字符串、数字、元组等其他容器模型。字典的每个键值key=>value对用冒号:分割,每个对之间用逗号,...

Python3.9版本新特性:字典合并操作的详细解读

处于测试阶段的Python3.9版本中有一个新特性:我们在使用Python字典时,将能够编写出更可读、更紧凑的代码啦!Python版本你现在使用哪种版本的Python?3.7分?3.5分?还是2.7...

python 自学,字典3(一些例子)(python字典有哪些基本操作)

例子11;如何批量复制字典里的内容2;如何批量修改字典的内容3;如何批量修改字典里某些指定的内容...

Python3.9中的字典合并和更新,几乎影响了所有Python程序员

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

Python3大字典:《Python3自学速查手册.pdf》限时下载中

最近有人会想了,2022了,想学Python晚不晚,学习python有前途吗?IT行业行业薪资高,发展前景好,是很多求职群里严重的香饽饽,而要进入这个高薪行业,也不是那么轻而易举的,拿信工专业的大学生...

python学习——字典(python字典基本操作)

字典Python的字典数据类型是基于hash散列算法实现的,采用键值对(key:value)的形式,根据key的值计算value的地址,具有非常快的查取和插入速度。但它是无序的,包含的元素个数不限,值...

324页清华教授撰写【Python 3 菜鸟查询手册】火了,小白入门字典

如何入门学习python...

Python3.9中的字典合并和更新,了解一下

全文共2837字,预计学习时长9分钟Python3.9正在积极开发,并计划于今年10月发布。2月26日,开发团队发布了alpha4版本。该版本引入了新的合并(|)和更新(|=)运算符,这个新特性几乎...

python3基础之字典(python中字典的基本操作)

字典和列表一样,也是python内置的一种数据结构。字典的结构如下图:列表用中括号[]把元素包起来,而字典是用大括号{}把元素包起来,只不过字典的每一个元素都包含键和值两部分。键和值是一一对应的...

取消回复欢迎 发表评论:

请填写验证码