基于Java的guava开源库工具类

作者:丽大佬的小跟班 时间:2022-04-07 05:37:53 

目录
  • 基于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开源库工具类

前言:

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

  • LoadingCache(本地缓存)

  • Multimap 和 Multiset

  • BiMap

  • Table(表)

  • Sets和Maps(交并差)

  • EventBus(事件)

  • StopWatch(秒表)

  • Files(文件操作)

  • RateLimiter(限流器)

  • Guava Retry(重试)

1、guava的maven配置引入 


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

2、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);

3、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

4、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));

5、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"));

6、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}

7、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"));

8、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);

9、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

10、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耗时趋于平滑

11、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);

来源:https://www.cnblogs.com/cscw/p/14899119.html

标签:Java,guava工具
0
投稿

猜你喜欢

  • 关于MyBatis模糊查询的几种实现方式

    2023-05-09 04:23:12
  • Spring AOP如何自定义注解实现审计或日志记录(完整代码)

    2022-03-28 02:19:34
  • Android圆形旋转菜单开发实例

    2023-09-06 11:42:52
  • SpringBoot整合Apollo配置中心快速使用详解

    2022-12-25 17:00:34
  • Spring框架七大模块简单介绍

    2023-03-10 10:25:23
  • java 如何计算同比增长工具类

    2023-11-09 08:50:35
  • Java定时器Timer使用方法详解

    2023-08-25 17:32:20
  • Android中子线程和UI线程通信详解

    2023-03-21 00:05:10
  • Mybatis 入门之MyBatis环境搭建(第一篇)

    2023-03-15 16:09:32
  • Java打印九九乘法表代码详情

    2022-03-14 17:42:14
  • C# 调用命令行执行Cmd命令的操作

    2022-08-03 10:43:26
  • 解决IDEA的Terminal中文乱码问题

    2022-05-06 01:31:08
  • Java Spring WEB应用实例化如何实现

    2022-05-20 04:26:35
  • C#设计模式之工厂模式

    2023-07-10 13:43:33
  • intellij idea创建第一个动态web项目的步骤方法

    2023-04-16 15:47:20
  • Android实现九宫格横向左右滑动

    2022-03-06 13:09:47
  • 详解C# 不能用于文件名的字符

    2023-03-05 07:44:45
  • 基于获取JAVA路径,包括CLASSPATH外的路径的方法详解

    2022-12-20 21:30:03
  • C#中循环语句:while、for、foreach的使用

    2022-05-01 02:42:55
  • Android webview与js交换JSON对象数据示例

    2022-10-19 18:36:18
  • asp之家 软件编程 m.aspxhome.com