龙空技术网

开源利器Guava之好用到哭的核心类库集合 「collections」

胖哥杂谈之 3287

前言:

现时兄弟们对“java核心类库”可能比较珍视,兄弟们都想要剖析一些“java核心类库”的相关知识。那么小编也在网上搜集了一些对于“java核心类库””的相关资讯,希望你们能喜欢,姐妹们一起来学习一下吧!

首先感谢大家的阅读,如果感兴趣,欢迎关注+点赞+留言讨论。

说起Guava,Java界应该是无人不知无人不晓,毕竟是Google内部使用并开源出来的Java工具类库,Google的很多项目都在使用Guava,相信经过Google线上这么多年的使用优化和打磨,Guava的类库的性能得到了非常好的验证,大家大可放心使用。

下面就开始介绍今天写这篇文章的目的,那就是:为了一个迟到的承诺。

今年7月底我曾经写过一篇介绍Guava的文章,链接如下:Java界的开源利器Guava,这么牛的干货用起来。

当时只是简单介绍了下Guava的功能和入门配置,但因为Guava的核心工具类库很多,一篇文章无法详细讲解每个核心类库,所以我在文章末尾发起了一个投票,想看看大家对这些核心类库有什么想法,最想学习哪个类库的使用方法。想着等待时间长点,这样用户的投票结果相对来说有意义,于是今天看了一些投票结果,发现大家对Guava的集合类库-collections投票人数较多,占比79%,所以今天就专门说一下Guava的集合类库。

话说这么少的人数投票,好可怜啊,好惨一男的,还请大家多多关注。

Guava的所有集合类库都在com/google/common/collect包里,大家如果想查看源代码的话,直接GitHub下载最新的mater分支,进入到该package里就可以学习了。

Guava 的集合类是对 JDK 集合类的扩展,Guava沿着JDK中原生集合的路线提供了更多的工具方法:适用于所有集合的静态方法,那么Guava的集合类增加了哪些具体类型呢?下面咱就来一一细说:

一、不可修改的集合-Immutable Collections

在写代码的时候,我们经常需要用到不可变对象,尤其是不可变集合,这在一些特定业务场景非常有用,比如:

1. 线程安全场景下,不可变对象是非常好的选择;

2. 可以当做常量使用;

3. 不受信任的库可以直接使用;

有些人或许会说,JDK本身的Collection也有不可变的版本,可以通过使用Collections.unmodifiableXXX 方法来实现。是的,没错,JDK也可以实现,但是他的实现是有缺陷的,下面咱就一个List为例说一下这个问题。

JDK版本的不可变List代码如下:

 List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,4,5)); List<Integer> umList = Collections.unmodifiableList(list);

上面代码中umList经过一层转换后是不可变对象,但是他的原值list对象确是可变的,umList只是持有了一个list的引用,可以通过修改list的值来达到修改umList的目的,这也就说明了JDK版本的不可变集合不是真正的不可变,是有很大缺陷的。

那么我们再来看一下Guava如何实现不可变集合:

ImmutableCollection icList = ImmutableList.of(1, 2, 3, 4, 5);

就这么简单一句代码,就声明了一个真正不可变的list集合icList,是不是很简洁方便?

上面的代码以ImmutableList举例,但是Guava还提供了ImmutableSet,ImmutableMap,ImmutableCollection等类,可以根据需要的数据结构分别调用。

二、Set的计数器-Multiset

JDK中Set集合是不可以添加重复元素,而且元素是无顺序的,但Multiset是可以放入重复元素,并对这些元素进行计数。

那么关于Multiset我们可以这么理解,它耦合了2种数据结构:ArrayList和Map<E, Integer>,当添加元素,获取集合大小和循环时可以当做普通的ArrayList来使用,但当调用查询接口时,当做Map使用,比如count(Object obj)这个方法就是查询obj在Multiset中的个数,就直接把obj当做Map的key,查询结果value当做obj出现的个数。

这样解释一番,是不是很容易理解了?

三、value也是集合的Map-Multimap

简单点说,Multimap就是Map<K, List<V>> or Map<K, Set<V>> 类似的数据结构,Guava只是把这种复杂点的结构重新包装成一个新的类型,方便大家使用,简洁代码,方便阅读,据说代码简洁可以加快人们的思考速度,提升工作效率,哈哈。

通常来说不会直接使用 Multimap 接口,而是使用 ListMultimap 或者 SetMultimap ,对应将 key 映射到 List 或者 Set 。

最直接构建 Multimap 的方式是使用 MultimapBuilder,这种方式允许用户自定义 key 和 value 应该有的样式,当然也可以用create()方法,这也是我最常用的方式:

 ArrayListMultimap<String, String> userSign = ArrayListMultimap.create(); userSign.put("zhangsan", "2019-05-01"); userSign.put("zhangsan", "2019-05-02"); List<String> zhangsanSign = userSign.get("zhangsan");

下载了Guava的源码就可以发现,其实他里面就是用Map<String,List>来实现的,这是定义的地方:

四、value也不可以重复的双向Map-BiMap

这个数据结构比较强大了,很明显就是key和value都是不可以重复的,而且可以根据key或value来查询对方,实现了双向互查,是不是很强大?

这个类是真的实现了JDK的Map接口的,使用它必须保证key和value都没有重复值.因为他支持根据value获取key,即将HashMap的key和value进行调换。

使用方式也很简单,理解了其底层的数据结构,用起来就会很顺手:

 BiMap<String, String> m = HashBiMap.create(); m.put("pf", "111"); String value = m.get("pf"); String key = m.inverse().get("111");
五、多层嵌套的Map-Table

其实这个table的底层数据结构也是工作中很常见的,就是Map<String,Map<String,Object>>的解决方案。我们工作中经常碰到多个索引一个结果的时候,直接用Map<String,Map<String,Object>>也是可以的,但实在是太难看了,不便于阅读。

Guava就基于这个原因提供了Table这个类,可以很优雅的实现这个数据结构,使用方式很简单,大家可以看下例子:

 Table<Integer, Integer, String> tt = HashBasedTable.create(); tt.put(1, 2, "huyan"); String name = tt.get(1, 2); Map<Integer, String> row = tt.row(1); Map<Integer, String> colum = tt.column(1); Set<Table.Cell<Integer, Integer, String>> ha = tt.cellSet();

看一下源码就会发现,其实Table底层也是使用两个map的嵌套实现的,但是Java语言嘛,讲究的就是一个封装,虽然我们可以自己实现,但是我们应该做的是去学习一下好的实现方法,看懂,理解并且能够在其他场景应用类似的思想,而不是每次都要自己写两个map.毕竟现成好用的轮子,在适用的场景下还是应该多多使用加深理解。

那么Guava中新增的5种集合类型就已经介绍完了,大家可以根据文中的例子好好理解下每个结构的定义,来加深理解其使用场景。

如果遗漏或者错误,欢迎指正,多谢!

标签: #java核心类库