基于Java的guava開源庫(kù)工具類
基于Java的guava開源庫(kù)工具類
前言:
平時(shí)我們都會(huì)封裝一些處理緩存或其他的小工具。但每個(gè)人都封裝一次,重復(fù)造輪子,有點(diǎn)費(fèi)時(shí)間。有沒有一些好的工具庫(kù)推薦-guava。guava是谷歌基于java封裝好的開源庫(kù),它的性能、實(shí)用性,比我們自己造的輪子更好,畢竟谷歌出品,下面介紹下幾個(gè)常用的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 在實(shí)際場(chǎng)景中有著非常廣泛的使用,通常情況下如果遇到需要大量時(shí)間計(jì)算或者緩存值的場(chǎng)景,就應(yīng)當(dāng)將值保存到緩存中。LoadingCache 和 ConcurrentMap 類似,但又不盡相同。最大的不同是 ConcurrentMap 會(huì)永久的存儲(chǔ)所有的元素值直到他們被顯示的移除,但是 LoadingCache 會(huì)為了保持內(nèi)存使用合理會(huì)根據(jù)配置自動(dòng)將過(guò)期值移除
通常情況下,Guava caching 適用于以下場(chǎng)景:
- 花費(fèi)一些內(nèi)存來(lái)?yè)Q取速度
- 一些 key 會(huì)被不止一次被調(diào)用
- 緩存內(nèi)容有限,不會(huì)超過(guò)內(nèi)存空間的值,Guava caches 不會(huì)存儲(chǔ)內(nèi)容到文件或者到服務(wù)器外部,如果有此類需求考慮使用 Memcached, Redis
LoadingCache 不能緩存 null key
CacheBuilder 構(gòu)造 LoadingCache 參數(shù)介紹
CacheBuilder 方法參數(shù) | 描述 |
---|---|
initialCapacity(int initialCapacity) | 緩存池的初始大小 |
concurrencyLevel(int concurrencyLevel) | 設(shè)置并發(fā)數(shù) |
maximumSize(long maximumSize) | 緩存池大小,在緩存項(xiàng)接近該大小時(shí), Guava開始回收舊的緩存項(xiàng) |
weakValues() | 設(shè)置value的存儲(chǔ)引用是虛引用 |
softValues() | 設(shè)置value的存儲(chǔ)引用是軟引用 |
expireAfterWrite(long duration, TimeUnit unit) | 設(shè)置時(shí)間對(duì)象沒有被寫則對(duì)象從內(nèi)存中刪除(在另外的線程里面不定期維護(hù)) |
expireAfterAccess(long duration, TimeUnit unit) | 設(shè)置時(shí)間對(duì)象沒有被讀/寫訪問則對(duì)象從內(nèi)存中刪除(在另外的線程里面不定期維護(hù)) |
refreshAfterWrite(long duration, TimeUnit unit) | 和expireAfterWrite類似,不過(guò)不立馬移除key,而是在下次更新時(shí)刷新,這段時(shí)間可能會(huì)返回舊值 |
removalListener( RemovalListener<? super K1, ? super V1> listener) | 監(jiān)聽器,緩存項(xiàng)被移除時(shí)會(huì)觸發(fā) |
build(CacheLoader<? super K1, V1> loader) | 當(dāng)數(shù)據(jù)不存在時(shí),則使用loader加載數(shù)據(jù) |
LoadingCache V get(K key),
獲取緩存值,如果鍵不存在值,將調(diào)用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的特點(diǎn)其實(shí)就是可以包含有幾個(gè)重復(fù)Key的value,可以put進(jìn)入多個(gè)不同value但是相同的key,但是又不會(huì)覆蓋前面的內(nèi)容
示例:
//Multimap: key-value key可以重復(fù),value也可重復(fù) 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 有一個(gè)相對(duì)有用的場(chǎng)景,就是跟蹤每種對(duì)象的數(shù)量,所以可以用來(lái)進(jìn)行數(shù)量統(tǒng)計(jì)
示例:
//MultiSet: 無(wú)序+可重復(fù) count()方法獲取單詞的次數(shù) 增強(qiáng)了可讀性+操作簡(jiǎn)單 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的鍵必須唯一,值也必須唯一,可以實(shí)現(xiàn)value和key互轉(zhuǎn)
示例:
BiMap<Integer,String> biMap = HashBiMap.create(); biMap.put(1,"lwl"); biMap.put(2,"csc"); BiMap<String, Integer> map = biMap.inverse(); // value和key互轉(zhuǎn) map.forEach((v, k) -> System.out.println(v + "-" + k));
5、Table
Table<R,C,V> table = HashBasedTable.create();,
由泛型可以看出,table由雙主鍵R(行),C(列)共同決定,V是存儲(chǔ)值- 新增數(shù)據(jù):
table.put(R,C,V)
- 獲取數(shù)據(jù):
V v = table.get(R,C)
- 遍歷數(shù)據(jù):
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對(duì)應(yīng)的value System.out.println(tables.get("csc","lwl"));
6、Sets和Maps
// 不可變集合的創(chuàng)建 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());; -------------結(jié)果------------- {c=3} {b=(2, 20)} {a=1} {d=4}
7、EventBus
- EventBus是Guava的事件處理機(jī)制,是設(shè)計(jì)模式中的觀察者模式(生產(chǎn)/消費(fèi)者編程模型)的優(yōu)雅實(shí)現(xiàn)。對(duì)于事件監(jiān)聽和發(fā)布訂閱模式
- EventBus內(nèi)部實(shí)現(xiàn)原理不復(fù)雜,EventBus內(nèi)部會(huì)維護(hù)一個(gè)Multimap<Class<?>, Subscriber> map,key就代表消息對(duì)應(yīng)的類(不同消息不同類,區(qū)分不同的消息)、value是一個(gè)Subscriber,Subscriber其實(shí)就是對(duì)應(yīng)消息處理者。如果有消息發(fā)布就去這個(gè)map里面找到這個(gè)消息對(duì)應(yīng)的Subscriber去執(zhí)行
使用示例:
@Data @AllArgsConstructor public class OrderMessage { String message; } //使用 @Subscribe 注解,表明使用dealWithEvent 方法處理 OrderMessage類型對(duì)應(yīng)的消息 //可以注解多個(gè)方法,不同的方法 處理不同的對(duì)象消息 public class OrderEventListener { @Subscribe public void dealWithEvent(OrderMessage event) { System.out.println("內(nèi)容:" + event.getMessage()); } } ------------------------------------- // new AsyncEventBus(String identifier, Executor executor); EventBus eventBus = new EventBus("lwl"); eventBus.register(new OrderEventListener()); // 發(fā)布消息 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("邏輯代碼運(yùn)行耗時(shí):"+nanos);
9、Files文件操作
數(shù)據(jù)寫入
File newFile = new File("D:/text.txt"); Files.write("this is a test".getBytes(), newFile); //再次寫入會(huì)把之前的內(nèi)容沖掉 Files.write("csc".getBytes(), newFile); //追加寫 Files.append("lwl", newFile, Charset.defaultCharset());
文本數(shù)據(jù)讀取
File newFile = new File("E:/text.txt"); List<String> lines = Files.readLines(newFile, Charset.defaultCharset());
其他操作
方法 | 描述 |
---|---|
Files.copy(File from, File to) | 復(fù)制文件 |
Files.deleteDirectoryContents(File directory) | 刪除文件夾下的內(nèi)容(包括文件與子文件夾) |
Files.deleteRecursively(File file) | 刪除文件或者文件夾 |
Files.move(File from, File to) | 移動(dòng)文件 |
Files.touch(File file) | 創(chuàng)建或者更新文件的時(shí)間戳 |
Files.getFileExtension(String file) | 獲得文件的擴(kuò)展名 |
Files.getNameWithoutExtension(String file) | 獲得不帶擴(kuò)展名的文件名 |
Files.map(File file, MapMode mode) | 獲取內(nèi)存映射buffer |
10、RateLimiter
//RateLimiter 構(gòu)造方法,每秒限流permitsPerSecond public static RateLimiter create(double permitsPerSecond) //每秒限流 permitsPerSecond,warmupPeriod 則是數(shù)據(jù)初始預(yù)熱時(shí)間,從第一次acquire 或 tryAcquire 執(zhí)行開時(shí)計(jì)算 public static RateLimiter create(double permitsPerSecond, Duration warmupPeriod) //獲取一個(gè)令牌,阻塞,返回阻塞時(shí)間 public double acquire() //獲取 permits 個(gè)令牌,阻塞,返回阻塞時(shí)間 public double acquire(int permits) //獲取一個(gè)令牌,超時(shí)返回 public boolean tryAcquire(Duration timeout) ////獲取 permits 個(gè)令牌,超時(shí)返回 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"); --------------- 結(jié)果 ------------------------- 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
- 因?yàn)镽ateLimiter滯后處理的,所以第一次無(wú)論取多少都是零秒
- 可以看到前四次的acquire,花了三秒時(shí)間去預(yù)熱數(shù)據(jù),在第五次到第八次的acquire耗時(shí)趨于平滑
11、Guava Retry
maven引入
<dependency> <groupId>com.github.rholder</groupId> <artifactId>guava-retrying</artifactId> <version>2.0.0</version> </dependency>
RetryerBuilder 構(gòu)造方法
RetryerBuilder方法 | 描述 |
---|---|
withRetryListener | 重試監(jiān)聽器 |
withWaitStrategy | 失敗后重試間隔時(shí)間 |
withStopStrategy | 停止策略 |
withBlockStrategy | 阻塞策略BlockStrategy |
withAttemptTimeLimiter | 執(zhí)行時(shí)間限制策略 |
retryIfException | 發(fā)生異常,則重試 |
retryIfRuntimeException | 發(fā)生RuntimeException異常,則重試 |
retryIfExceptionOfType(Class<? extends Throwable> ex) | 發(fā)生ex異常,則重試 |
retryIfException(Predicate<Throwable> exceptionPredicate) | 對(duì)異常判斷,是否重試 |
retryIfResult(Predicate<V> resultPredicate) | 對(duì)返回結(jié)果判斷,是否重試 |
Retryer<Boolean> retryer = RetryerBuilder.<Boolean>newBuilder() .retryIfException() .retryIfResult(Predicates.equalTo(false)) .withAttemptTimeLimiter(AttemptTimeLimiters.fixedTimeLimit(1, TimeUnit.SECONDS)) .withStopStrategy(StopStrategies.stopAfterAttempt(5)) .build(); //Retryer調(diào)用 retryer.call(() -> true);
以上就是基于Java的guava開源庫(kù)工具類的詳細(xì)內(nèi)容,更多關(guān)于guava開源庫(kù)工具類的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!希望大家以后多多支持腳本之家!
相關(guān)文章
Java和MySQL數(shù)據(jù)庫(kù)中關(guān)于小數(shù)的保存問題詳析
在Java和MySQL中小數(shù)的精度可能會(huì)受到限制,如float類型的小數(shù)只能精確到6-7位,double類型也只能精確到15-16位,這篇文章主要給大家介紹了關(guān)于Java和MySQL數(shù)據(jù)庫(kù)中關(guān)于小數(shù)的保存問題,需要的朋友可以參考下2024-01-01FastDFS分布式文件系統(tǒng)環(huán)境搭建及安裝過(guò)程解析
這篇文章主要介紹了FastDFS分布式文件系統(tǒng)環(huán)境搭建及安裝過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08