前言

平时我们都会封装一些处理缓存或其他的小工具。但每个人都封装一次,重复造轮子,有点费时间。有没有一些好的工具库推荐-guava。guava是谷歌基于java封装好的开源库,它的性能、实用性,比我们自己造的轮子更好,毕竟谷歌出品,下面介绍下几个常用的guava工具类

  • LoadingCache(本地缓存)
  • Multimap 和 Multiset
  • BiMap
  • Table(表)
  • Sets和Maps(交并差)
  • EventBus(事件)
  • StopWatch(秒表)
  • Files(文件操作)
  • RateLimiter(限流器)
  • Guava Retry(重试)

关注公众号,一起交流,微信搜一搜: 潜行前行

guava的maven配置引入

<dependency>
  <groupId>com.google.guava</groupId>
  <artifactId>guava</artifactId>
  <version>27.0-jre</version>
</dependency>

LoadingCache

  • LoadingCache 在实际场景中有着非常广泛的使用,通常情况下如果遇到需要大量时间计算或者缓存值的场景,就应当将值保存到缓存中。LoadingCache 和 ConcurrentMap 类似,但又不尽相同。最大的不同是 ConcurrentMap 会永久的存储所有的元素值直到他们被显示的移除,但是 LoadingCache 会为了保持内存使用合理会根据配置自动将过期值移除
  • 通常情况下,Guava caching 适用于以下场景:
    • 花费一些内存来换取速度
    • 一些 key 会被不止一次被调用
    • 缓存内容有限,不会超过内存空间的值,Guava caches 不会存储内容到文件或者到服务器外部,如果有此类需求考虑使用 Memcached, Redis
  • LoadingCache 不能缓存 null key
  • CacheBuilder 构造 LoadingCache 参数介绍
CacheBuilder 方法参数 描述
initialCapacity(int initialCapacity) 缓存池的初始大小
concurrencyLevel(int concurrencyLevel) 设置并发数
maximumSize(long maximumSize) 缓存池大小,在缓存项接近该大小时, Guava开始回收旧的缓存项
weakValues() 设置value的存储引用是虚引用
softValues() 设置value的存储引用是软引用
expireAfterWrite(long duration, TimeUnit unit) 设置时间对象没有被写则对象从内存中删除(在另外的线程里面不定期维护)
expireAfterAccess(long duration, TimeUnit unit) 设置时间对象没有被读/写访问则对象从内存中删除(在另外的线程里面不定期维护)
refreshAfterWrite(long duration, TimeUnit unit) 和expireAfterWrite类似,不过不立马移除key,而是在下次更新时刷新,这段时间可能会返回旧值
removalListener( RemovalListener<? super K1, ? super V1> listener) 监听器,缓存项被移除时会触发
build(CacheLoader<? super K1, V1> loader) 当数据不存在时,则使用loader加载数据
  • LoadingCache V get(K key), 获取缓存值,如果键不存在值,将调用CacheLoader的load方法加载新值到该键中
  • 示例
LoadingCache<Integer,Long> cacheMap = CacheBuilder.newBuilder().initialCapacity(10)
.concurrencyLevel(10)
.expireAfterAccess(Duration.ofSeconds(10))
.weakValues()
.recordStats()
.removalListener(new RemovalListener<Integer,Long>(){
@Override
public void onRemoval(RemovalNotification<Integer, Long> notification) {
System.out.println(notification.getValue());
}
})
.build(new CacheLoader<Integer,Long>(){
@Override
public Long load(Integer key) throws Exception {
return System.currentTimeMillis();
}
});
cacheMap.get(1);

Multimap 和 MultiSet

  • Multimap的特点其实就是可以包含有几个重复Key的value,可以put进入多个不同value但是相同的key,但是又不会覆盖前面的内容
  • 示例
//Multimap: key-value  key可以重复,value也可重复
Multimap<String, String> multimap = ArrayListMultimap.create();
multimap.put("csc","1");
multimap.put("lwl","1");
multimap.put("csc","1");
multimap.put("lwl","one");
System.out.println(multimap.get("csc"));
System.out.println(multimap.get("lwl"));
---------------------------
[1, 1]
[1, one]
  • MultiSet 有一个相对有用的场景,就是跟踪每种对象的数量,所以可以用来进行数量统计
  • 示例
//MultiSet: 无序+可重复   count()方法获取单词的次数  增强了可读性+操作简单
Multiset<String> set = HashMultiset.create();
set.add("csc");
set.add("lwl");
set.add("csc");
System.out.println(set.size());
System.out.println(set.count("csc"));
---------------------------
3
2

BiMap

  • BiMap的键必须唯一,值也必须唯一,可以实现value和key互转
  • 示例
BiMap<Integer,String> biMap = HashBiMap.create();
biMap.put(1,"lwl");
biMap.put(2,"csc");
BiMap<String, Integer> map = biMap.inverse(); // value和key互转
map.forEach((v, k) -> System.out.println(v + "-" + k));

Table

  • Table<R,C,V> table = HashBasedTable.create();,由泛型可以看出,table由双主键R(行),C(列)共同决定,V是存储值
  • 新增数据:table.put(R,C,V)
  • 获取数据:V v = table.get(R,C)
  • 遍历数据: Set<R> set = table.rowKeySet(); Set<C> set = table.columnKeySet();   
  • 示例
// 双键的Map Map--> Table-->rowKey+columnKey+value
Table<String, String, Integer> tables = HashBasedTable.create();
tables.put("csc", "lwl", 1);
//row+column对应的value
System.out.println(tables.get("csc","lwl"));

Sets和Maps

// 不可变集合的创建
ImmutableList<String> iList = ImmutableList.of("csc", "lwl");
ImmutableSet<String> iSet = ImmutableSet.of("csc", "lwl");
ImmutableMap<String, String> iMap = ImmutableMap.of("csc", "hello", "lwl", "world");

set的交集, 并集, 差集

HashSet setA = newHashSet(1, 2, 3, 4, 5);
HashSet setB = newHashSet(4, 5, 6, 7, 8);
//并集
SetView union = Sets.union(setA, setB);
//差集 setA-setB
SetView difference = Sets.difference(setA, setB);
//交集
SetView intersection = Sets.intersection(setA, setB);

map的交集,并集,差集

HashMap<String, Integer> mapA = Maps.newHashMap();
mapA.put("a", 1);mapA.put("b", 2);mapA.put("c", 3);
HashMap<String, Integer> mapB = Maps.newHashMap();
mapB.put("b", 20);mapB.put("c", 3);mapB.put("d", 4);
MapDifference<String, Integer> mapDifference = Maps.difference(mapA, mapB);
//mapA 和 mapB 相同的 entry
System.out.println(mapDifference.entriesInCommon());
//mapA 和 mapB key相同的value不同的 entry
System.out.println(mapDifference.entriesDiffering());
//只存在 mapA 的 entry
System.out.println(mapDifference.entriesOnlyOnLeft());
//只存在 mapB 的 entry
System.out.println(mapDifference.entriesOnlyOnRight());;
-------------结果-------------
{c=3}
{b=(2, 20)}
{a=1}
{d=4}

EventBus

  • EventBus是Guava的事件处理机制,是设计模式中的观察者模式(生产/消费者编程模型)的优雅实现。对于事件监听和发布订阅模式
  • EventBus内部实现原理不复杂,EventBus内部会维护一个Multimap<Class<?>, Subscriber> map,key就代表消息对应的类(不同消息不同类,区分不同的消息)、value是一个Subscriber,Subscriber其实就是对应消息处理者。如果有消息发布就去这个map里面找到这个消息对应的Subscriber去执行
  • 使用示例
@Data
@AllArgsConstructor
public class OrderMessage {
String message;
}
//使用 @Subscribe 注解,表明使用dealWithEvent 方法处理 OrderMessage类型对应的消息
//可以注解多个方法,不同的方法 处理不同的对象消息
public class OrderEventListener {
@Subscribe
public void dealWithEvent(OrderMessage event) {
System.out.println("内容:" + event.getMessage());
}
}
-------------------------------------
// new AsyncEventBus(String identifier, Executor executor);
EventBus eventBus = new EventBus("lwl");
eventBus.register(new OrderEventListener());
// 发布消息
eventBus.post(new OrderMessage("csc"));

StopWatch

Stopwatch stopwatch = Stopwatch.createStarted();
for(int i=0; i<100000; i++){
// do some thing
}
long nanos = stopwatch.elapsed(TimeUnit.MILLISECONDS);
System.out.println("逻辑代码运行耗时:"+nanos);

Files文件操作

  • 数据写入
File newFile = new File("D:/text.txt");
Files.write("this is a test".getBytes(), newFile);
//再次写入会把之前的内容冲掉
Files.write("csc".getBytes(), newFile);
//追加写
Files.append("lwl", newFile, Charset.defaultCharset());
  • 文本数据读取
File newFile = new File("E:/text.txt");
List<String> lines = Files.readLines(newFile, Charset.defaultCharset());
  • 其他操作
方法 描述
Files.copy(File from, File to) 复制文件
Files.deleteDirectoryContents(File directory) 删除文件夹下的内容(包括文件与子文件夹)
Files.deleteRecursively(File file) 删除文件或者文件夹
Files.move(File from, File to) 移动文件
Files.touch(File file) 创建或者更新文件的时间戳
Files.getFileExtension(String file) 获得文件的扩展名
Files.getNameWithoutExtension(String file) 获得不带扩展名的文件名
Files.map(File file, MapMode mode) 获取内存映射buffer

RateLimiter

//RateLimiter 构造方法,每秒限流permitsPerSecond
public static RateLimiter create(double permitsPerSecond)
//每秒限流 permitsPerSecond,warmupPeriod 则是数据初始预热时间,从第一次acquire 或 tryAcquire 执行开时计算
public static RateLimiter create(double permitsPerSecond, Duration warmupPeriod)
//获取一个令牌,阻塞,返回阻塞时间
public double acquire()
//获取 permits 个令牌,阻塞,返回阻塞时间
public double acquire(int permits)
//获取一个令牌,超时返回
public boolean tryAcquire(Duration timeout)
////获取 permits 个令牌,超时返回
public boolean tryAcquire(int permits, Duration timeout)
  • 使用示例
RateLimiter limiter = RateLimiter.create(2, 3, TimeUnit.SECONDS);
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
System.out.println("get one permit cost time: " + limiter.acquire(1) + "s");
--------------- 结果 -------------------------
get one permit cost time: 0.0s
get one permit cost time: 1.331672s
get one permit cost time: 0.998392s
get one permit cost time: 0.666014s
get one permit cost time: 0.498514s
get one permit cost time: 0.498918s
get one permit cost time: 0.499151s
get one permit cost time: 0.488548s
  • 因为RateLimiter滞后处理的,所以第一次无论取多少都是零秒
  • 可以看到前四次的acquire,花了三秒时间去预热数据,在第五次到第八次的acquire耗时趋于平滑

Guava Retry

  • maven引入
<dependency>
<groupId>com.github.rholder</groupId>
<artifactId>guava-retrying</artifactId>
<version>2.0.0</version>
</dependency>
  • RetryerBuilder 构造方法
RetryerBuilder方法 描述
withRetryListener 重试监听器
withWaitStrategy 失败后重试间隔时间
withStopStrategy 停止策略
withBlockStrategy 阻塞策略BlockStrategy
withAttemptTimeLimiter 执行时间限制策略
retryIfException 发生异常,则重试
retryIfRuntimeException 发生RuntimeException异常,则重试
retryIfExceptionOfType(Class<? extends Throwable> ex) 发生ex异常,则重试
retryIfException(Predicate<Throwable> exceptionPredicate) 对异常判断,是否重试
retryIfResult(Predicate<V> resultPredicate) 对返回结果判断,是否重试
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder()
.retryIfException()
.retryIfResult(Predicates.equalTo(false))
.withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(1, TimeUnit.SECONDS))
.withStopStrategy(StopStrategies.stopAfterAttempt(5))
.build();
//Retryer调用
retryer.call(() -> true);

参考文章

工具篇:介绍几个好用的guava工具类的更多相关文章

  1. Tools:downloading and Building EDK II工具篇:安装/使用EDKII源代码获取/编译工具[2.3]

    Tools:Installing and using the Required Tools for downloading and Building EDK II工具篇:安装/使用EDKII源代码获取 ...

  2. 【Java/Android性能优2】Android性能调优工具TraceView介绍

    本文参考:http://www.trinea.cn/android/android-traceview/ Android自带的TraceView堪比java的性能调优工具visualvm线程视图,可以 ...

  3. 【工具篇】利用DBExportDoc V1.0 For MySQL自动生成数据库表结构文档

    对于DBA或开发来说,如何规范化你的数据库表结构文档是灰常之重要的一件事情.但是当你的库,你的表排山倒海滴多的时候,你就会很头疼了. 推荐一款工具DBExportDoc V1.0 For MySQL( ...

  4. 国内首篇介绍JanOS物联网操作系统的文章 - 如何把你的手机主板打造成物联网平台

    天地会珠海分舵注:如无意外,您现在正在看的将是国内首篇且是唯一一篇介绍炙手可热的物联网的操作系统JanOS的文章!不信你去百度!希望大家能喜欢.但本文只是引言,更多信息请还是访问JanOS的官网:ht ...

  5. 大数据工具篇之Hive与MySQL整合完整教程

    大数据工具篇之Hive与MySQL整合完整教程 一.引言 Hive元数据存储可以放到RDBMS数据库中,本文以Hive与MySQL数据库的整合为目标,详细说明Hive与MySQL的整合方法. 二.安装 ...

  6. GC参考手册 —— GC 调优(工具篇)

    JVM 在程序执行的过程中, 提供了GC行为的原生数据.那么, 我们就可以利用这些原生数据来生成各种报告.原生数据(raw data) 包括: 各个内存池的当前使用情况, 各个内存池的总容量, 每次G ...

  7. 介绍一个axios调试好用的工具:axios-mock-adapter

    上一篇文章中写到用promise时应注意的问题,这一篇文章继续介绍一个可以和axios库配合的好工具: axios-mock-adapter.axios-mock-adapter可以用来拦截http请 ...

  8. Caffe学习系列——工具篇:神经网络模型结构可视化

    Caffe学习系列——工具篇:神经网络模型结构可视化 在Caffe中,目前有两种可视化prototxt格式网络结构的方法: 使用Netscope在线可视化 使用Caffe提供的draw_net.py ...

  9. spring boot 学习(九)小工具篇:?秒防刷新

    注解 + 拦截器:?秒防刷新 小工具篇:工具许多都是我以前在 github 之类开源平台找到的小工具类,作者的信息什么的许多都忘了.先说声不好意思了.若有相关信息,麻烦提醒一下~ 解释 所谓的?秒防刷 ...

随机推荐

  1. 使用 cmake 来搭建跨平台的应用程序框架:C语言版本

    目录 一.前言 二.示例代码说明 1. 功能描述 2. 文件结构 3. cmake 构建步骤 4. Utils 目录说明 5. Application 目录说明 三.Linux 系统下操作步骤 1. ...

  2. 【Spring浅析】一、 BeanFactory 有啥可说的?

    阅读 Spring 源码,BeanFactory 是避不了的存在.而大家常见的使用场景,也是以下形式: ConfigurableApplicationContext ctx = SpringAppli ...

  3. SpringBoot中获取上下文

    在实际开发中,有时候会根据某个bean的名称或class到Spring容器中获取对应的Bean.这里只做个简单的记录,方便后续自查. @Component public class SpringCon ...

  4. Word·去掉复制粘贴自动添加的空格

    阅文时长 | 0.05分钟 字数统计 | 145.6字符 主要内容 | 1.引言&背景 2.声明与参考资料 『Word·去掉复制粘贴自动添加的空格』 编写人 | SCscHero 编写时间 | ...

  5. 微服务&#183;API文档

    阅文时长 | 3.92分钟 字数统计 | 2754.05字符 主要内容 | 1.什么是API文档 2.API文档的使用 3.声明与参考资料 『微服务·API文档』 编写人 | SCscHero 编写时 ...

  6. 【BIGDATA】Grafana告警之webhook的坑

    近日搭建一套基于ELK&Grafana的监控告警平台,目的是将生产端某性能日志导入ES中,通过Grafana进行可视化监测,同时设置告警. 告警内容推送到自建的webhook服务后,转发到指定 ...

  7. 强哥HTML学习笔记

    html 浏览器的选择:1.火狐2.ie3.chrome4.mac5.opera 安装两款插件:1.firebug2.web develope html页面元素:1.doctype2.htmlhead ...

  8. 使用LUKS加密你的磁盘

    计算机数据的安全,保密性在现在的生活中显得越来越重要.随着数字化的时代的来临,越来越多的数据被数字化,特别是更多有关于我们隐私的数据在不断生成,甚至还有我们需要离线保存的密钥等.而且通常我们使用磁盘, ...

  9. python基础之进程、线程、协程篇

    一.多任务(多线程) 多线程特点:(1)线程的并发是利用cpu上下文的切换(是并发,不是并行)(2)多线程执行的顺序是无序的(3)多线程共享全局变量(4)线程是继承在进程里的,没有进程就没有线程(5) ...

  10. C语言规范:C89、C90、C95、C99

    本文转载 [K&R C] 1978 年,Dennis Ritchie 和 Brian Kernighan 合作推出了<The C Programming Language>的第一版 ...