关于java:Guava-HashMultimap使用及注意事项

36次阅读

共计 4341 个字符,预计需要花费 11 分钟才能阅读完成。

Guava HashMultimap 应用及注意事项

hello,各位大佬上午 | 中午 | 下午 | 早晨 | 凌晨好,我是一灰灰,明天给大家介绍一个绝对根底的知识点 HashMultmap;

guava 基本上能够说是 java 开发我的项目中,大概率会引入的包,明天介绍的配角是一个非凡的容器 — HashMultmap,能够简略的将它的数据结构了解为Map<K, Set<V>>

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

<!– more –>

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](https://blog.hhui.top)
- 微博地址: [小灰灰 Blog](https://weibo.com/p/1005052169825577/home)
- QQ:一灰灰 /3302797840
- 微信公众号:** 一灰灰 blog**

![QrCode](https://spring.hhui.top/spring-blog/imgs/info/info.png)

正文完
 0