java的Guava工具包介绍
集合
普通集合
List list = Lists.newArrayList(); Set set = Sets.newHashSet(); Map map = Maps.newHashMap();
Set 取交集、并集、差集
HashSetsetA = Sets.newHashSet(1, 2, 3, 4, 5); HashSet setB = Sets.newHashSet(4, 5, 6, 7, 8); Sets.SetView union = Sets.union(setA, setB); System.out.println("union:" + union); Sets.SetView difference = Sets.difference(setA, setB); System.out.println("difference:" + difference); Sets.SetView intersection = Sets.intersection(setA, setB); System.out.println("intersection:" + intersection);
map 取交集、并集、差集
HashMap mapA = Maps.newHashMap(); mapA.put("a", 1); mapA.put("b", 2); mapA.put("c", 3); HashMap mapB = Maps.newHashMap(); mapB.put("b", 20); mapB.put("c", 3); mapB.put("d", 4); MapDifference differenceMap = Maps.difference(mapA, mapB); Map> entriesDiffering = differenceMap.entriesDiffering(); //左边差集Map entriesOnlyLeft = differenceMap.entriesOnlyOnLeft(); //右边差集Map entriesOnlyRight = differenceMap.entriesOnlyOnRight(); //交集Map entriesInCommon = differenceMap.entriesInCommon(); System.out.println(entriesDiffering); // {b=(2, 20)}System.out.println(entriesOnlyLeft); // {a=1}System.out.println(entriesOnlyRight); // {d=4}System.out.println(entriesInCommon); // {c=3}
不可变集合(immutable)
不可变集合的特性有:
- 在多线程操作下,是线程安全的;
- 所有不可变集合会比可变集合更有效的利用资源;
- 中途不可改变。
ImmutableListiList = ImmutableList.of(12,54,87); ImmutableSet iSet = ImmutableSet.of(354,54,764,354); ImmutableMap iMap = ImmutableMap.of("k1", 453, "k2", 534);
以上 Immutable 开头的相关集合类的 add、remove 方法都被声明为 deprecated。当你手误点到了这些方法发现是 deprecated 的时候你不会还想着使用吧。
注意:每个Guava immutable集合类的实现都拒绝 null 值。
有趣的集合
MultiSet: 无序+可重复
我们映像中的 Set 应该是无序的,元素不可重复的。MultiSet 颠覆了三观,因为它可以重复。
定义一个 MultiSet 并添加元素:
Multisetset = HashMultiset.create(); set.add(3); set.add(3); set.add(4); set.add(5); set.add(4);
你还可以添加指定个数的同一个元素:
set.add(7, 3);
这表示你想添加 3 个 7。
打印出来的 MultiSet 也很有意思:
[3 x 2, 4 x 2, 5, 7 x 3]
2个3,2个4,一个5,3个7。
获取某个元素的个数:
int count = set.count(3);
这个工具类确实很有意思,帮我们实现了 word count。
Multimap :key 可以重复的 map
这个 map 也很有意思。正常的 map 为了区分不同的 key,它倒好,直接给你来一样的 key 。
Multimap map = LinkedHashMultimap.create(); map.put("key", "haha"); map.put("key", "haha1"); Collection key = map.get("key"); System.out.println(key);
使用很简单,用一个 key 可以获取到该 key 对应的两个值,结果用 list 返回。恕我无知,我还没想到这个 map 能够使用的场景。

文章图片
Multimap 提供了多种实现:
Multimap 实现 | key 字段类型 | value 字段类型 |
---|---|---|
ArrayListMultimap | HashMap | ArrayList |
HashMultimap | HashMap | HashSet |
LinkedListMultimap | LinkedHashMap | LinkedList |
LinkedHashMultimap | LinkedHashMap | LinkedHashSet |
TreeMultimap | TreeMap | TreeSet |
ImmutableListMultimap | ImmutableMap | ImmutableList |
ImmutableSetMultimap | ImmutableMap | ImmutableSet |
双向 Map
(Bidirectional Map) 键与值都不能重复
这个稍稍正常一点。如果 key 重复了则会覆盖 key ,如果 value 重复了则会报错。
public static void main(String[] args) {BiMap biMap = HashBiMap.create(); biMap.put("key", "haha"); biMap.put("key", "haha1"); biMap.put("key1", "haha"); String value = https://www.it610.com/article/biMap.get("key"); System.out.println(value); }
上面的示例中键 ”key“ 有两个,运行可以发现 get 的时候会用 ”haha1" 覆盖 ”haha“,另外 value 为 ”haha“ 也有两个,你会发现运行上面的代码不会报错,这是因为 ”key“ 对应的 value 已经被 "haha1" 覆盖了。否则是会报错。
双键 map - 超级实用
双键的 map ,我突然感觉我发现了新大陆。比如我有一个业务场景是:根据职位和部门将公司人员区分开来。key 可以用职位 + 部门组成一个字符串,那我们有了双键 map 之后就没这种烦恼。
public static void main(String[] args) {Table> tables = HashBasedTable.create(); tables.put("财务部", "总监", Lists.newArrayList()); tables.put("财务部", "职员",Lists.newArrayList()); tables.put("法务部", "助理",Lists.newArrayList()); System.out.println(tables); }
工具类 JDK里大家耳熟能详的是
Collections
这个集合工具类, 提供了一些基础的集合处理转换功能, 但是实际使用里很多需求并不是简单的排序, 或者比较数值大小, 然后 Guava 在此基础上做了许多的改进优化, 可以说是 Guava 最为成熟/流行的模块之一。- 数组相关:Lists
- 集合相关:Sets
- map 相关:Maps
Joiner 做为连接符的使用非常简单,下例是将 list 转为使用连接符连接的字符串:
Listlist = Lists.newArrayList(); list.add(34); list.add(64); list.add(267); list.add(865); String result = Joiner.skipNulls().on("-").join(list); System.out.println(result); 输出:34-64-267-865
将 map 转为自定义连接符连接的字符串:
Map map = Maps.newHashMap(); map.put("key1", 45); map.put("key2",234); String result = Joiner.on(",").withKeyValueSeparator("=").join(map); System.out.println(result); 输出:key1=45,key2=234
分隔符 Splitter 的使用也很简单:
String str = "1-2-3-4-5-6"; List list = Splitter.on("-").splitToList(str); System.out.println(list); 输出:[1, 2, 3, 4, 5, 6]
如果字符串中带有空格,还可以先去掉空格:
String str = "1-2-3-4-5-6"; List list = Splitter.on("-").omitEmptyStrings().trimResults().splitToList(str); System.out.println(list);
将 String 转为 map:
String str = "key1=54,key2=28"; Map map = Splitter.on(",").withKeyValueSeparator("=").split(str); System.out.println(map); 输出:{key1=54, key2=28}
Comparator 的实现
Java 提供了 Comparator 可以用来对对象进行排序。Guava 提供了排序器 Ordering 类封装了很多实用的操作。
Ordering 提供了一些有用的方法:
- natural() 对可排序类型做自然排序,如数字按大小,日期按先后排序
- usingToString() 按对象的字符串形式做字典排序[lexicographical ordering]
- from(Comparator) 把给定的Comparator转化为排序器
- reverse() 获取语义相反的排序器
- nullsFirst() 使用当前排序器,但额外把null值排到最前面。
- nullsLast() 使用当前排序器,但额外把null值排到最后面。
- compound(Comparator) 合成另一个比较器,以处理当前排序器中的相等情况。 lexicographical() 基于处理类型T的排序器,返回该类型的可迭代对象Iterable 的排序器。
- onResultOf(Function) 对集合中元素调用Function,再按返回值用当前排序器排序。
UserInfo build = UserInfo.builder().uid(234L).gender(1).build(); UserInfo build1 = UserInfo.builder().uid(4354L).gender(0).build(); OrderingbyOrdering = Ordering.natural().nullsFirst().onResultOf((Function >) input -> input.getGender()); System.out.println(byOrdering.compare(build1, build));
build 的 gender 大于 build1 的,所以返回 -1,反之返回 1。
统计中间代码运行时间
Stopwatch 类提供了时间统计的功能,相当于帮你封装了调用 System.currentTimeMillis() 的逻辑。
Stopwatch stopwatch = Stopwatch.createStarted(); try {//TODO 模拟业务逻辑Thread.sleep(2000L); } catch (InterruptedException e) {e.printStackTrace(); }long nanos = stopwatch.elapsed(TimeUnit.SECONDS); System.out.println(nanos);
Guava Cache - 本地缓存组件
Guava Cache 在日常的使用中非常地频繁,甚至都没有意识到这是第三方提供的工具类而是把它当成了 JDK 自带的实现。
// LoadingCache是Cache的缓存实现LoadingCache cache = CacheBuilder.newBuilder()//设置缓存大小.maximumSize(1000)//设置到期时间.expireAfterWrite(10, TimeUnit.MINUTES)//设置缓存里的值两分钟刷新一次.refreshAfterWrite(2, TimeUnit.MINUTES)//开启缓存的统计功能.recordStats()//构建缓存.build(new CacheLoader() {//此处实现如果根据key找不到value需要去如何获取@Overridepublic Object load(String s) throws Exception {return new Object(); }//如果批量加载有比反复调用load更优的方法则重写这个方法@Overridepublic Map loadAll(Iterable keys) throws Exception {return super.loadAll(keys); }});
设置本地缓存使用 CacheBuilder.newBuilder(),支持设置缓存大小,缓存过期时间,缓存刷新频率等等。如果你想统计缓存的命中率, Guava Cache 也提供了这种能力帮你汇总当前缓存是否有效。
同时缓存如果因为某种原因未自动刷新或者清除,Guava Cache 也支持用户手动调用 API 刷新或者清除缓存。
cache.invalidateAll(); //清除所有缓存项//清理的时机:在写操作时顺带做少量的维护工作,或者偶尔在读操作时做——如果写操作实在太少的话//如果想自己维护则可以调用Cache.cleanUp(); cache.cleanUp(); //另外有时候需要缓存中的数据做出变化重载一次,这个过程可以异步执行cache.refresh("key");
单机限流工具类 - RateLimiter
常用的限流算法有 漏桶算法、令牌桶算法。这两种算法各有侧重点:
- 漏桶算法:漏桶的意思就像一个漏斗一样,水一滴一滴的滴下去,流出是匀速的。当访问量过大的时候这个漏斗就会积水。漏桶算法的实现依赖队列,一个处理器从队头依照固定频率取出数据进行处理。如果请求量过大导致队列堆满那么新来的请求就会被抛弃。漏桶一般按照固定的速率流出。
- 令牌桶则是存放固定容量的令牌,按照固定速率从桶中取出令牌。初始给桶中添加固定容量令牌,当桶中令牌不够取出的时候则拒绝新的请求。令牌桶不限制取出令牌的速度,只要有令牌就能处理。所以令牌桶允许一定程度的突发,而漏桶主要目的是平滑流出。
- 平滑突发限流(SmoothBursty)
- 平滑预热限流(SmoothWarmingUp)
RateLimiter r = RateLimiter.create(5); while (true) {System.out.println("get 1 tokens: " + r.acquire() + "s"); }输出:get 1 tokens: 0.0sget 1 tokens: 0.197059sget 1 tokens: 0.195338sget 1 tokens: 0.196918sget 1 tokens: 0.19955sget 1 tokens: 0.199062sget 1 tokens: 0.195589sget 1 tokens: 0.195061s......
设置每秒放置的令牌数为 5 个,基本 0.2s 一次符合每秒 5 个的设置。保证每秒不超过 5 个达到了平滑输出的效果。
在没有请求使用令牌桶的时候,令牌会先创建好放在桶中,所以此时如果突然有突发流量进来,由于桶中有足够的令牌可以快速响应。RateLimiter 在没有足够令牌发放时采用滞后处理的方式,前一个请求获取令牌所需等待的时间由下一次请求来承受。
平滑预热限流并不会像平滑突发限流一样先将所有的令牌创建好,它启动后会有一段预热期,逐步将分发频率提升到配置的速率。
比如下面例子创建一个平均分发令牌速率为 2,预热期为 3 分钟。由于设置了预热时间是 3 秒,令牌桶一开始并不会 0.5 秒发一个令牌,而是形成一个平滑线性下降的坡度,频率越来越高,在 3 秒钟之内达到原本设置的频率,以后就以固定的频率输出。这种功能适合系统刚启动需要一点时间来“热身”的场景。
RateLimiter r = RateLimiter.create(2, 3, TimeUnit.SECONDS); while (true) {System.out.println("get 1 tokens: " + r.acquire(1) + "s"); System.out.println("get 1 tokens: " + r.acquire(1) + "s"); System.out.println("end"); }输出:get 1 tokens: 0.0sget 1 tokens: 1.33068sendget 1 tokens: 0.995792sget 1 tokens: 0.662838sendget 1 tokens: 0.494775sget 1 tokens: 0.497293sendget 1 tokens: 0.49966sget 1 tokens: 0.49625send
从上面的输出看前面两次获取令牌都很耗时,往后就越来越趋于平稳。
今天给大家介绍的常用的 Guava 工具类就这些,不过 JDK8 开始 Java官方 API 也在完善,比如像字符串相关的功能 JDK也很强大。都是工具,哪个好用就用哪个。
【java的Guava工具包介绍】到此这篇关于java的Guava工具包介绍的文章就到这了,更多相关Guava工具包内容请搜索脚本之家以前的文章或继续浏览下面的相关文章,希望大家以后多多支持脚本之家!
推荐阅读
- 热闹中的孤独
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 放屁有这三个特征的,请注意啦!这说明你的身体毒素太多
- 一个人的旅行,三亚
- 布丽吉特,人生绝对的赢家
- 慢慢的美丽
- 尽力
- 一个小故事,我的思考。
- 家乡的那条小河
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量