<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          工具篇:介紹幾個好用的guava工具類

          共 11092字,需瀏覽 23分鐘

           ·

          2021-07-13 19:16

          1 前言

          平時我們都會封裝一些處理緩存或其他的小工具。但每個人都封裝一次,重復(fù)造輪子,有點費時間。有沒有一些好的工具庫推薦-guava。guava是谷歌基于java封裝好的開源庫,它的性能、實用性,比我們自己造的輪子更好,畢竟谷歌出品,下面介紹下幾個常用的guava工具類

          • LoadingCache(本地緩存)

          • Multimap 和 Multiset

          • BiMap

          • Table(表)

          • Sets和Maps(交并差)

          • EventBus(事件)

          • StopWatch(秒表)

          • Files(文件操作)

          • RateLimiter(限流器)

          • Guava Retry(重試)

           

          2 guava的maven配置引入

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

           

          3 LoadingCache

          • LoadingCache 在實際場景中有著非常廣泛的使用,通常情況下如果遇到需要大量時間計算或者緩存值的場景,就應(yīng)當(dāng)將值保存到緩存中。LoadingCache 和 ConcurrentMap 類似,但又不盡相同。最大的不同是 ConcurrentMap 會永久的存儲所有的元素值直到他們被顯示的移除,但是 LoadingCache 會為了保持內(nèi)存使用合理會根據(jù)配置自動將過期值移除

          • 通常情況下,Guava caching 適用于以下場景:

            • 花費一些內(nèi)存來換取速度

            • 一些 key 會被不止一次被調(diào)用

            • 緩存內(nèi)容有限,不會超過內(nèi)存空間的值,Guava caches 不會存儲內(nèi)容到文件或者到服務(wù)器外部,如果有此類需求考慮使用 Memcached, Redis

          • LoadingCache 不能緩存 null key

          • CacheBuilder 構(gòu)造 LoadingCache 參數(shù)介紹

          • 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);

           

          4 Multimap 和 MultiSet

          • Multimap的特點其實就是可以包含有幾個重復(fù)Key的value,可以put進(jìn)入多個不同value但是相同的key,但是又不會覆蓋前面的內(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"));
          ---------------------------
          [11]
          [1, one]
          • MultiSet 有一個相對有用的場景,就是跟蹤每種對象的數(shù)量,所以可以用來進(jìn)行數(shù)量統(tǒng)計

          • 示例

          //MultiSet: 無序+可重復(fù)   count()方法獲取單詞的次數(shù)  增強了可讀性+操作簡單
          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

           

          5 BiMap

          • BiMap的鍵必須唯一,值也必須唯一,可以實現(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));

           

          6 Table

          • Table<R,C,V> table = HashBasedTable.create();,由泛型可以看出,table由雙主鍵R(行),C(列)共同決定,V是存儲值

          • 新增數(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對應(yīng)的value
          System.out.println(tables.get("csc","lwl"));

           

          7 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(12345);  
          HashSet setB = newHashSet(45678); 
          //并集
          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=(220)}
          {a=1}
          {d=4}

           

          8 EventBus

          • EventBus是Guava的事件處理機制,是設(shè)計模式中的觀察者模式(生產(chǎn)/消費者編程模型)的優(yōu)雅實現(xiàn)。對于事件監(jiān)聽和發(fā)布訂閱模式

          • EventBus內(nèi)部實現(xiàn)原理不復(fù)雜,EventBus內(nèi)部會維護(hù)一個Multimap<Class<?>, Subscriber> map,key就代表消息對應(yīng)的類(不同消息不同類,區(qū)分不同的消息)、value是一個Subscriber,Subscriber其實就是對應(yīng)消息處理者。如果有消息發(fā)布就去這個map里面找到這個消息對應(yīng)的Subscriber去執(zhí)行

          • 使用示例

          @Data
          @AllArgsConstructor
          public class OrderMessage {
              String message;
          }
          //使用 @Subscribe 注解,表明使用dealWithEvent 方法處理 OrderMessage類型對應(yīng)的消息
          //可以注解多個方法,不同的方法 處理不同的對象消息
          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"));

           

          9 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);


          10 Files文件操作

          • 數(shù)據(jù)寫入

          File newFile = new File("D:/text.txt");
          Files.write("this is a test".getBytes(), newFile);
          //再次寫入會把之前的內(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());
          • 其他操作


          11 RateLimiter

          //RateLimiter 構(gòu)造方法,每秒限流permitsPerSecond
          public static RateLimiter create(double permitsPerSecond) 
          //每秒限流 permitsPerSecond,warmupPeriod 則是數(shù)據(jù)初始預(yù)熱時間,從第一次acquire 或 tryAcquire 執(zhí)行開時計算
          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(23, 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
          • 因為RateLimiter滯后處理的,所以第一次無論取多少都是零秒

          • 可以看到前四次的acquire,花了三秒時間去預(yù)熱數(shù)據(jù),在第五次到第八次的acquire耗時趨于平滑

           

          12 Guava Retry

          • maven引入

          <dependency>
          <groupId>com.github.rholder</groupId>
          <artifactId>guava-retrying</artifactId>
          <version>2.0.0</version>
          </dependency>
          • RetryerBuilder 構(gòu)造方法

          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);
          • spring也有對應(yīng)的重試機制,相關(guān)文章可以看看重試框架Guava-Retry和spring-Retry[1]歡迎指正文中錯誤(故事純屬虛構(gòu),如有雷同純屬巧合)


          13 參考文章

          • Google guava工具類的介紹和使用[2]
          • 重試框架Guava-Retry和spring-Retry[3]
          • 超詳細(xì)的Guava RateLimiter限流原理解析[4]

          參考資料

          [1]

          重試框架Guava-Retry和spring-Retry: https://blog.csdn.net/zzzgd_666/article/details/84377962

          [2]

          Google guava工具類的介紹和使用: https://blog.csdn.net/wwwdc1012/article/details/82228458

          [3]

          重試框架Guava-Retry和spring-Retry: https://blog.csdn.net/zzzgd_666/article/details/84377962

          [4]

          超詳細(xì)的Guava RateLimiter限流原理解析: https://zhuanlan.zhihu.com/p/60979444



          有道無術(shù),術(shù)可成;有術(shù)無道,止于術(shù)

          歡迎大家關(guān)注Java之道公眾號


          好文章,我在看??

          瀏覽 59
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天射天天草 | 精品免费久久久久 | 色婷婷五月天 | 国产成人精品影视 | 成人大香蕉最新视频 |