Java项目Guava包 HashMultimap使用及注意事项

目录
  • 1. 数据模型介绍
  • 2. 简单使用介绍
    • 2.1 容器创建
    • 2.2 添加元素
    • 2.3 移除元素
    • 2.4 替换元素
    • 2.5 获取元素及遍历
    • 2.6 输出所有的key
    • 2.7 输出所有的value
  • 3. 小结

今天给大家介绍一个相对基础的知识点 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的基础容器实现一个类似的容器,如何优雅的去实现呢? 这里就给了一个标准答案,强烈推荐有兴趣的小伙伴瞅一下

到此这篇关于Java项目Guava包 HashMultimap使用及注意事项的文章就介绍到这了,更多相关java HashMultimap使用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java编程guava RateLimiter实例解析

    本文主要研究的是Java编程guava RateLimiter的相关内容,具体如下. 令牌桶算法(token bucket algorithm) 场景1 在流量监管中的应用 约定访问速率(CAR)是流量监管常用技术之一,可以应用在端口进和出方向,一般应用在入方向,它的监管原理如图1所示. a. 按特定的速率向令牌桶投放令牌 b. 根据预设的匹配规则先对报文进行分类,不符合匹配规则的报文不需要经过令牌桶的处理,直接发送: c. 符合匹配规则的报文,则需要令牌桶进行处理.当桶中有足够的令牌则报文可以

  • Java Guava排序器Ordering原理及代码实例

    一 创建排序器 排序器:可以用来为构建复杂的比较器,以完成集合排序的功能: 本质上来说,Ordering 实例无非就是一个特殊的Comparator 实例. Ordering把很多基于Comparator的静态方法(如Collections.max)包装为自己的实例方法(非静态方法), 并且提供了链式调用方法,来定制和增强现有的比较器 //创建排序器 @Test public void createOreing(){ //对可排序类型做自然排序,如数字按大小,日期按先后排序 Ordering<C

  • 基于Java的guava开源库工具类

    目录 基于Java的guava开源库工具类 1.guava的maven配置引入 2.LoadingCache 3.Multimap 和 MultiSet 4.BiMap 5.Table 6.Sets和Maps 7.EventBus 8.StopWatch 9.Files文件操作 10.RateLimiter 11.Guava Retry 基于Java的guava开源库工具类 前言: 平时我们都会封装一些处理缓存或其他的小工具.但每个人都封装一次,重复造轮子,有点费时间.有没有一些好的工具库推荐-

  • java的Guava工具包介绍

    集合 普通集合 List<String> list = Lists.newArrayList(); Set<String> set = Sets.newHashSet(); Map<String, String> map = Maps.newHashMap(); Set 取交集.并集.差集 HashSet<Integer> setA = Sets.newHashSet(1, 2, 3, 4, 5); HashSet<Integer> setB =

  • Java guava monitor监视器线程的使用详解

    Maven依赖 <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>31.0.1-jre</version> </dependency> 代码 不废话上代码. package com.huyi.csdn.tools; import cn.hutool.core.thread.Thread

  • Java基于Guava Retrying实现重试功能

    在接口调用中由于各种原因,可能会重置失败的任务,使用Guava-Retrying可以方便的实现重试功能. 首先,需要引用Guava-Retrying的包 <dependency> <groupId>com.github.rholder</groupId> <artifactId>guava-retrying</artifactId> <version>2.0.0</version> </dependency>

  • Java项目Guava包 HashMultimap使用及注意事项

    目录 1. 数据模型介绍 2. 简单使用介绍 2.1 容器创建 2.2 添加元素 2.3 移除元素 2.4 替换元素 2.5 获取元素及遍历 2.6 输出所有的key 2.7 输出所有的value 3. 小结 今天给大家介绍一个相对基础的知识点 HashMultmap: guava基本上可以说是java开发项目中,大概率会引入的包,今天介绍的主角是一个特殊的容器 -- HashMultmap,可以简单的将它的数据结构理解为Map<K, Set<V>> 那么为什么会突然想到介绍一下它

  • java项目jar包与jdk的版本不兼容的问题解决

    这篇文章主要介绍了java项目jar包与jdk的版本不兼容的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在我们搭建框架或者引入jar包是,总是会因为版本不统一导致版本兼容问题,而且错误还不好找, 今天就遇到了一个问题Unsupported major.minor version 52.0并记录下解决方案 错误原因: 我当时使用的是jdk7,因为公司是传统行业,所以jdk的版本不是很到,而我现在需要搭建一套新的项目框架,我引入了一些最

  • 关于weblogic部署Java项目的包冲突问题的解决

    我们可能会用各种应用服务部署我们的Java应用,比如Tomcat.WAS.weblogic等.Tomcat和WAS可能会比较少遇到一些奇怪的问题,但是用weblogic部署项目则经常遇到一些比如包冲突问题,路径问题等奇怪但又常见的问题. 今天我就讲讲关于weblogic部署Java项目包冲突的问题.下面我举个例子: 当我在weblogic部署Java项目之后,启动没报任何错,没有异常.但是当我操作某个功能的时候页面就报错了: 后台报了这个错: Root cause of ServletExcep

  • 浅谈java项目与javaweb项目导入jar包的区别

    现在的项目基本上都是java web项目,所以导入jar包会出现问题,主要介绍一下java项目与javaweb项目的区别: java项目: 在classLoader加载jar和class的时候,是分开加载的,一般jar导入分两种: 1.在web-inf下的lib中直接引入 2.在user library上引入 无论以上哪种引入,jar包都能加载并且运行,classLoader会智能加载(本地JRE运行) javaweb项目: 不是通过本地的JRE运行的,而是部署到web服务器(比如tomcat,

  • 详解在LINUX上部署带有JAR包的JAVA项目

    在LINUX上部署带有JAR包的JAVA项目 首先eclipse上要装上一个小插件,叫做Fat Jar 点击Fat Jar 红框里选上主类点击Next 如图把勾打上 在该路径下找到jar包 通过ftp协议把jar包放在linux服务器下 进入到jar包路径 输入指令 java -jar XXX.jar 运行成功! 注意!!!!!!!!!!!!!!!! 当你断开服务器连接时,工程会停止! 所以要用下面的指令 指令:nohup java -jar XXX.jar 通过指令ps -ef | grep

  • IntelliJ IDEA Java项目手动添加依赖 jar 包的方法(图解)

    1. 事先下载完成需要的javacsv.jar包.  java项目在没有导入该jar包之前,显示如下图所示 2. 点击 File -> Project Structure(快捷键 Ctrl + Alt + Shift + s),点击Project Structure界面左侧的"Modules"显示下图界面 3. 在 "Dependencies" 标签界面下,点击右边绿色的 "+"号,选择第一个选项"JARs or director

  • 将Java项目打包成可执行的jar包

    一.通过 eclipse 自带打包 测试项目: Main.java package com.bug; import org.junit.Test; public class Main { public static void main(String[] args) { test(); } @Test public static void test() { System.out.println("HelloWorld"); System.out.println("HelloWo

  • 在idea中将java项目中的单个类打包成jar包操作

    JAR文件的全称是Java Archive File,即Java档案文件.JAR文件是一种压缩文件,与常见的ZIP压缩文件兼容,被称为JAR包. JAR文件与zip文件的主要区别是在JAR文件中默认包含了一个名为META-INF/MANIFEST.MF的清单文件,这个清单文件是在生成JAR文件时系统自动创建的. 打包jar包 1.先创建一个要打包成jar包的类 2.File -> Project Structrue -> Artifacts -> + -> JAR -> fr

  • java eclipse 整个项目或包查找只定字符串并替换操作

    java eclipse经常会用到整个类进行查找,ctrl+f,然后replaceall(XX,toXX).但是最近要对webservice上的项目进行检查,里面的运行程序不能有system.out.println这样的语句,因为服务器上的控制台输出会存储到一个指定路径的文件里,超过9gtomcat就会运行变慢,甚至挂掉.所以这里要用,ctrl+h,开启全项目或者全包搜索,用法如下: 1.选中项目名称或者包名称位置,ctrl+h 2弹出的界面中选取,file Search,在其中输入要查找的字符

  • IDEA创建Java项目导出Jar包运行

    第一步:创建Java项目 下图中的勾去掉: 下图中输入项目名称,选择存放位置(可随意选择) 上图中点击Finish后即可完成java项目的创建. 第一次创建会出现: 不是第一次可能会出现: 第二步:编写程序 输入包名,创建class,创建main方法. 三处都可以运行main方法,红框为结果. 第三步:导出jar包 选择main方法的java文件 点击确认后会生成下图中的文件 生成jar包 第四步:运行jar包 把jar包拷贝到E盘(随意)下,按住shift+鼠标右键,在此处打开命令行窗口,执行

随机推荐