1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

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

        共 11092字,需瀏覽 23分鐘

         ·

        2021-07-13 19:16

        1 前言

        平時我們都會封裝一些處理緩存或其他的小工具。但每個人都封裝一次,重復(fù)造輪子,有點費(fèi)時間。有沒有一些好的工具庫推薦-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 適用于以下場景:

          • 花費(fèi)一些內(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ù)  增強(qiáng)了可讀性+操作簡單
        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的事件處理機(jī)制,是設(shè)計模式中的觀察者模式(生產(chǎn)/消費(fèi)者編程模型)的優(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("邏輯代碼運(yùn)行耗時:"+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)的重試機(jī)制,相關(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
        點贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

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

        手機(jī)掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            夜夜夜夜猛噜噜噜噜噜初音未来 | 少妇大叫受不了了爽爽爽摸摸 | 九九色九九 | 黄色操逼一级视频 | 97麻豆国产传媒成人影片 | 免费观看一级黄色片 | 特黄60分钟免费全过程 | 九九欧美 | 免费看裸体网站樱花 | 在线观看成人免费视频 |