还在使用集合类完成这些功能?不妨来看看 Guava 集合类!!!
楼下小黑哥 人气:0
日常开发中,小黑哥经常需要用到 Java 提供集合类完成各种需求。Java 集合类虽然非常强大实用,但是提供功能还是有点薄弱。
举个例子,小黑哥最近接到一个需求,从输入一个文档中,统计一个关键词出现的次数。代码如下:
![](https://img2020.cnblogs.com/other/1419561/202003/1419561-20200313073808852-1209478404.jpg)
虽然这个需求使用 `Map` 可以轻松搞定,但是小黑哥还是觉得这种写法有点笨拙,如果没有判空,将会导致 NPE 异常。
如果很多地方需要功能,我们就可以抽象出来,将其封装成工具类。
不过上面的功能大家就不需要自己封装,一款来自 **Google** 开源工具类-**Guava**,可以轻松的解决上面的统计问题。
## Guava 介绍
Guava 是一款 Google 开源工具类,包含许多 Google 内部 `Java` 项目依赖的核心类。Guava 扩展 Java 基础类工程,比如集合,并发等,也增加一些其他强大功能,比如缓存,限流等功能。
另外 Guava 推出一些类,如 `Optional`,甚至被 Java 开发者学习,后续增加到 JDK 中。
目前 [Guava Github 仓库](https://github.com/google/guava)已有 **36k star**,可以见到 Guava 受欢迎程度。
![](https://img2020.cnblogs.com/other/1419561/202003/1419561-20200313073809050-324423312.jpg)
Guava 核心功能包括多个模块,今天小黑哥主要带大家玩转 Guava 集合类。
## 扩展集合类
Guava 创造很多 JDK 没有,但是我们日常却明显有用的新集合类型。这些新类型使用 JDK 集合接口规范,所以使用方法与 JDK 集合框架差不多,并没有增加很多使用难度。
### Multiset
小黑哥第一次见到 `Multiset` 这个类,还以为是 `Set` 接口子类。实际上此『Set』,仅仅只是数学上集合概念。
`Multiset` 继承 JDK `Collection` 接口,我们可以多次增加相同的元素,另外 `Multiset` 最大特定将会为元素计数,我们可以将它类似等同为 `Map` 。
使用 `Multiset`可以轻松解决开头的问题。
![](https://img2020.cnblogs.com/other/1419561/202003/1419561-20200313073809183-1587978442.jpg)
使用 `Multiset` 简化了代码,并且再也不用担心新 **NPE** 的问题。
跟 JDK 集合类一样,`Multiset`也有许多子类。
![来源于 Github](https://img2020.cnblogs.com/other/1419561/202003/1419561-20200313073809294-232108898.jpg)
这里小黑哥提醒一下大家,虽然上面说过我们可以将 `Multiset` 看做 `Map`,但是 `Multiset` 可不是 `Map` 的子类,它可是 血统纯正的 `Collection` 子类。
### Multimap
小黑哥有时会在业务需求中使用 `Map `实现下面的需求。
```jav
a->[1,2,3] b->4,c->[6,5]
```
使用 `Map` + `List` 这种结构比较笨拙,并且代码实现也比较繁琐。`Multimap` 正式 Guava 中解决这种问题的新出的一个雷。
使用 `Multimap` 实现代码如下:
![](https://img2020.cnblogs.com/other/1419561/202003/1419561-20200313073809404-140991873.jpg)
这里小黑哥使用 `Multimap` 子类 `HashMultimap`,其行为类似为 `Map>`,也就是说 `Value` 对应的集合内部元素不能重复。如果需要保存的重复的元素我们可以使用 `ArrayListMultimap`。
`Multimap`还有其他子类,如图所示:
![来源于 Github](https://img2020.cnblogs.com/other/1419561/202003/1419561-20200313073809552-517452346.jpg)
### BiMap
`BiMap` 可以用来实现键值对的双向映射需求,这样我们就可以通过 `Key` 查找对对应的 `Value`,也可以使用 `Value` 查找对应的 `Key`。
这个需求如果使用 `Map` 实现,我们就不得不使用两个 `Map`,维护双向关系,并且任何改动还要保持同步。
![](https://img2020.cnblogs.com/other/1419561/202003/1419561-20200313073809700-845831701.jpg)
使用 `BiMap` 修改上面的代码:
![](https://img2020.cnblogs.com/other/1419561/202003/1419561-20200313073809808-1646676550.jpg)
这里需要注意,`BiMap#put`方法不能加入重复元素, 若加入,将会抛错。如果若特定值一定要替换,可以使用 `BiMap#forcePut`代替。
敲黑板,这个知识点记下来。小黑哥使用过程中,就踩过这个坑。
同样的 `BiMap` 也有各种实现类:
![来源于 Github](https://img2020.cnblogs.com/other/1419561/202003/1419561-20200313073809948-1969882288.jpg)
### 其他扩展集合类
Guava 另外还提供其他集合类,不过这些类使用起来有点复杂,小黑哥还未在业务代码中使用过,这里简单提下,感兴趣同学可以深入了解一下。
- Table
- ClassToInstanceMap
- RangeSet
- RangeMap
## 集合工具类
除了上面提到的新集合类以外,Guava 提供通用的工具类:
![来源于 Github](https://img2020.cnblogs.com/other/1419561/202003/1419561-20200313073810081-607737181.jpg)
这些工具类需对使用的方法,我们可以快速创建集合,分割集合,转化集合等。
### 快速创建集合实例
使用工具类,我们可以快速创建集合。例如:
```java
List list=Lists.newArrayList();
Set set=Sets.newHashSet();
Map map=Maps.newHashMap();
```
相比于 `new` 集合方法,Guava 方法创建方式更加简单。
```java
List list=new ArrayList();
Set set=new HashSet();
Map map=new HashMap();
```
Guava 工具类智能推导 `List` 泛型,再也不用两侧都重复写泛型了。
另外还可以指定集合类的初始化大小。
![](https://img2020.cnblogs.com/other/1419561/202003/1419561-20200313073810258-122686511.jpg)
### Lists.transform
`Lists#transform`方法可以替代繁琐 `for` 循环,将元素转化,创建一个新集合类。
![](https://img2020.cnblogs.com/other/1419561/202003/1419561-20200313073810405-644226866.jpg)
不过使用这个方法我们要**注意**一点。
`Lists#transform` 内部使用懒加载的机制,只有在调用获取的元素的时候,如 `result.get` 才会真正使用 `Function` 从源 `List` 获取元素,做相应的转化。**每次获取元素**都将会使用 `function` 进行转化。
所以使用 `Lists#transform` 得到 `List` 仅仅只是源 `List` 一个视图,任何对源 `List` 的元素修改,都将会被反应到创建之后的 `List` 。任何对创建之后 List 中的元素进行修改,都不会生效。下次再次读取元素时,将会发现相应修改的丢失了。。。
小黑哥之前就踩过这个坑,如果你有这种需求,可以使用以下方式创建一个新集合:
![](https://img2020.cnblogs.com/other/1419561/202003/1419561-20200313073810525-1110036160.jpg)
> JDK8 之前版本,小黑哥经常使用该方法转化 `List` 中的元素。不过你如果使用 JDK8,小黑哥还是推荐使用 Stream 流式编程。
### 交集并集差集
`Sets` 提供几个方法,可以快速求出两个 `Set` 集合的交集,并集以及差集。
![](https://img2020.cnblogs.com/other/1419561/202003/1419561-20200313073810714-929651750.png)
## 不可变集合
不可变(**Immutable**)集合,顾名思义集合不可以被修改。初始创建不可变集合时吗,需要传入数据源,创建完成之后,集合就再也不能修改,增加,删除元素,否则将会报错。
这是一种防御性策略,防止集合在后续操作中被修改,从而引发问题。
不可变集合优点在于:
- 由于不可变集合仅仅只能读,多线程并发天然安全
- 由于不可变集合固定不变,可以将其当做常量安全,不用单线其他人修改
- 不可变集合占用更少内存空间
- 不可变集合不可以被修改,所以不用担心其他程序任意修改集合
Guava 不可变集合支持 JDK 所有集合接口:
![](https://img2020.cnblogs.com/other/1419561/202003/1419561-20200313073810852-2062921527.jpg)
我们可以使用如下几种方式创建不可变集合,以 `ImmutableList` 为例:
![ImmutableList](https://img2020.cnblogs.com/other/1419561/202003/1419561-20200313073810997-1689931186.jpg)
```java
List fromList=Lists.newArrayList("点赞","关注");
// 从一个集合拷贝元素
ImmutableList.copyOf(fromList);
ImmutableList.of("关注","Java极客技术");
ImmutableList.builder().add("关注").addAll(fromList).build();
```
## 总结
这篇文章小黑哥带大家学习开源工具 Guava 集合的相关类使用方法,日常开发中我们善于使用这些工具类,不要自己重复造轮子。
本篇文章仅仅只是介绍 Guava 一小部分功能,还有很对功能,小黑哥也觉得很好用在。这里推荐大家去查看 Guava 官方 wiki,查看具体使用方法。
如果大家还想知道其他开源工具类,给小黑哥**点个赞**,下次给大家带来十分好用开源工具类~
![](https://img2020.cnblogs.com/other/1419561/202003/1419561-20200313073811119-1291858101.jpg)
> 欢迎关注我的公众号:程序通事,获得日常干货推送。如果您对我的专题内容感兴趣,也可以关注我的博客:[studyidea.cn](https://studyidea.cn)
加载全部内容