Google Guava

  • 1.以面向?qū)ο笏枷胩幚碜址?Joiner/Splitter/CharMatcher
    // 連接器
    private static final Joiner joiner = Joiner.on(",").skipNulls();

    // 分割器
    private static final Splitter spliter = Splitter.on(",").trimResults().omitEmptyStrings();
    public static void main(String[] args) {
        //把集合數(shù)組中的元素join在一起
        String join = joiner.join(Lists.newArrayList("a", null, "b", "", "  "));
        System.out.println("join=" + join);

        for (String tmp : spliter.split(" a, b,  null  ,,")){
            System.out.println("|" + tmp + "|");
        }
    }

輸出:
join=a,b,,
|a|
|b|
|null|

使用useForNull可以制定一個字符串替換null,而不是直接跳過null , 如下:

private static final Joiner joiner = Joiner.on(",").useForNull("wudy");

輸出: join=a,wudy,b,,

使用空白字符分割

private static final Splitter spliter = Splitter.on(CharMatcher.WHITESPACE).trimResults().omitEmptyStrings();
for (String tmp : spliter.split(" a, b,  null  ,  ,")){
            System.out.println("|" + tmp + "|");
        }

輸出:
|a,|
|b,|
|null|
|,|
|,|

按固定長度拆分,最后一段可能比給定長度短,但不會為空

private static final Splitter spliter = Splitter.fixedLength(3).trimResults().omitEmptyStrings();
for (String tmp : spliter.split(" a, b,  null  ,  ,   ")){
            System.out.println("|" + tmp + "|");
        }

輸出:
|a,|
|b,|
|n|
|ull|
|,|
|,|

字符串匹配器

  private static final CharMatcher charMatcherDigit = CharMatcher.DIGIT;
  private static final CharMatcher charMatcherAny = CharMatcher.ANY;

  public static void main(String[] args) {
        //只保留匹配的字符,其他移除
        System.out.println("只保留字符串的數(shù)字=" + charMatcherDigit.retainFrom("ashbx78i~!"));
        System.out.println("移除字符串的數(shù)字=" + charMatcherDigit.removeFrom("ashbx78i~!"));
        System.out.println("用?替換數(shù)字=" + charMatcherDigit.replaceFrom("ashbx78i~!", "?"));
        System.out.println("在字母a~f范圍或者等于n,全部替換為* |  " + charMatcherAny.inRange('a', 'f').or(charMatcherAny.is('n')).replaceFrom("xscfgvjhjkhdnass", "*"));
 }

輸出:
只保留字符串的數(shù)字=78
移除字符串的數(shù)字=ashbxi~!
用?替換數(shù)字=ashbx??i~!
在字母a~f范圍或者等于n,全部替換為* | xsgvjhjkh*ss

總結(jié):

  • 1.對于Joiner,常用的方法是 跳過NULL元素:skipNulls() / 對于NULL元素使用其他替代:useForNull(String)
    1. 對于Splitter,常用的方法是:trimResults()/omitEmptyStrings()。注意拆分的方式,有字符串,還有正則,還有固定長度分割
  • 3.joiner實(shí)例總是不可變的。用來定義joiner目標(biāo)語義的配置方法總會返回一個新的joiner實(shí)例。這使得joiner實(shí)例都是線程安全的,你可以將其定義為static final常量
  • 2.guava對JDK提供的原生類型操作進(jìn)行了擴(kuò)展
 public static void main(String[] args) {
        // 快速完成到集合的轉(zhuǎn)換
        List<Integer> list = Ints.asList(1,3,5,7,9);
        System.out.println(Ints.join(",", 1,3,1,4));

        // 原生類型的數(shù)組快速合并
        int[] intArray = Ints.concat(new int[]{1,2}, new int[]{3,4});
        System.out.println(intArray.length);

        //最大最小
        System.out.println("最大值=" + Ints.max(intArray) + "最小值=" + Ints.min(intArray));

        // 是否包含
        System.out.println("是否包含=" + Ints.contains(intArray, 1));

        // 集合到數(shù)組轉(zhuǎn)換
        int[] intArr = Ints.toArray(list);
        
    }

輸出:
1,3,1,4
4
最大值=4最小值=1
是否包含=true

總結(jié): guava提供了Bytes/Shorts/Ints/Iongs/Floats/Doubles/Chars/Booleans這些基本數(shù)據(jù)類型的擴(kuò)展支持

  • 3.對JDK集合的有效補(bǔ)充

灰色地帶:Multiset
JDK的集合,提供了有序且可以重復(fù)的List,無序且不可以重復(fù)的Set。那這里其實(shí)對于集合涉及到了2個概念,一個order,一個dups。那么List vs Set,and then some ?

image.png

Multiset是什么,我想上面的圖,你應(yīng)該了解它的概念了。Multiset就是無序的,但是可以重復(fù)的集合,它就是游離在List/Set之間的“灰色地帶”!
(至于有序的,不允許重復(fù)的集合嘛,guava還沒有提供,當(dāng)然在未來應(yīng)該會提供UniqueList,我猜的,哈哈)
重點(diǎn):Multiset自帶一個有用的功能,就是可以跟蹤每個對象的數(shù)量

   public static void main(String[] args) {
        HashMultiset<String> hashMultiset = HashMultiset.create();
        hashMultiset.add("a");
        hashMultiset.add("a");
        hashMultiset.add("b");
        hashMultiset.add("c");
        hashMultiset.add("b");
        System.out.println("size=" + hashMultiset.size());
        System.out.println("元素a的出現(xiàn)次數(shù)" + hashMultiset.count("a"));
    }

輸出:
size=5
元素a的出現(xiàn)次數(shù)2

  • 4.Immutable vs unmodifiable
// 先看一個unmodifiable的例子:
public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");

        List<String> readOnlyList = Collections.unmodifiableList(list);
//        readOnlyList.add("c"); //java.lang.UnsupportedOperationException
        list.add("c");
        System.out.println(readOnlyList.size());  // 3
    }

你看到JDK提供的unmodifiable的缺陷了嗎?
實(shí)際上,Collections.unmodifiableXxx所返回的集合和源集合是同一個對象,只不過可以對集合做出改變的API都被override,會拋出UnsupportedOperationException。
也即是說我們改變源集合,導(dǎo)致不可變視圖(unmodifiable View)也會發(fā)生變化。
當(dāng)然,在不使用guava的情況下,我們是怎么避免上面的問題的呢?

public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        // new Object: copy (Defensive Copies,保護(hù)性拷貝)
        List<String> readOnlyList = Collections.unmodifiableList(new ArrayList<String>(list));
        list.add("c");
        System.out.println(readOnlyList.size());  // 2
    }

使用Guava方式
guava提供了很多Immutable集合,比如ImmutableList/ImmutableSet/ImmutableSortedSet/ImmutableMap, ImmutableCOPY階段還考慮了線程的并發(fā)性等

public static void main(String[] args) {
        ImmutableList<String> immutableList = ImmutableList.of("a", "b", "c");
//        immutableList.add("d"); //java.lang.UnsupportedOperationException
        ArrayList<String> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add("c");
        ImmutableList<String> immutableList1 = ImmutableList.copyOf(list);
        list.add("d");
        // 視圖不會隨著源數(shù)據(jù)而改變,guava只讀設(shè)置安全可靠
        System.out.println("list size=" + list.size() + "  immutableList1 size=" + immutableList1.size() ); // list size=4  immutableList1 size=3
    }
// ImmutableMap例子
 ImmutableMap<String, String> immutableMap = ImmutableMap.of("name", "wudy", "phone", "13074491521");
 immutableMap.put("address", "sz"); // java.lang.UnsupportedOperationException
  • 5.一對多: Multimap

JDK提供給我們的Map是一個鍵,一個值,一對一的,那么在實(shí)際開發(fā)中,顯然存在一個KEY多個VALUE的情況(比如一個分類下的書本),我們往往這樣表達(dá):Map<k,List>,好像有點(diǎn)臃腫!臃腫也就算了,更加不爽的事,我們還得判斷KEY是否存在來決定是否new 一個LIST出來,有點(diǎn)麻煩!更加麻煩的事情還在后頭,比如遍歷,比如刪除

 public static void main(String[] args) {
        Multimap<String, String> multimap = ArrayListMultimap.create();
        multimap.put("phone", "13074491521");
        multimap.put("phone", "18973038382");
        multimap.put("name", "wudy");
        System.out.println(multimap.get("phone")); // [13074491521, 18973038382]
    }

友情提示下,guava所有的集合都有create方法,這樣的好處在于簡單,而且我們不必在重復(fù)泛型信息了。
get()/keys()/keySet()/values()/entries()/asMap()都是非常有用的返回view collection的方法。
Multimap的實(shí)現(xiàn)類有:ArrayListMultimap/HashMultimap/LinkedHashMultimap/TreeMultimap/ImmutableMultimap

  • 6.雙向BiMap

JDK提供的MAP讓我們可以find value by key,那么能不能通過find key by value呢,能不能KEYVALUE都是唯一的呢。這是一個雙向的概念,即forward+backward。
在實(shí)際場景中有這樣的需求嗎?比如通過用戶ID找到mail,也需要通過mail找回用戶名。沒有guava的時候,我們需要create forward map AND create backward map,and now just let guava do that for you.

 public static void main(String[] args) {
        HashBiMap<String, String> biMap = HashBiMap.create();
        biMap.put("wudy.yu", "13074491521");
        // value 重復(fù)會報錯
//        biMap.put("peter.li", "13074491521"); // java.lang.IllegalArgumentException: value already present: 13074491521

        // 強(qiáng)制覆蓋
        biMap.forcePut("peter.li", "13074491521");
        // 反轉(zhuǎn)為 value => key
        System.out.println(biMap.inverse().get("13074491521")); // peter.li

    }

biMap / biMap.inverse() / biMap.inverse().inverse() 它們是什么關(guān)系呢?
你可以稍微看一下BiMap的源碼實(shí)現(xiàn),實(shí)際上,當(dāng)你創(chuàng)建BiMap的時候,在內(nèi)部維護(hù)了2個map,一個forward map,一個backward map,并且設(shè)置了它們之間的關(guān)系。
因此,biMap.inverse() != biMap;biMap.inverse().inverse() == biMap

  • 7.多個keyTable

我們知道數(shù)據(jù)庫除了主鍵外,還提供了復(fù)合索引,而且實(shí)際中這樣的多級關(guān)系查找也是比較多的,當(dāng)然我們可以利用嵌套的Map來實(shí)現(xiàn):Map<k1,Map<k2,v2>>。為了讓我們的代碼看起來不那么丑陋,guava為我們提供了Table
Table涉及到3個概念:rowKey,columnKey,value,并提供了多種視圖以及操作方法讓你更加輕松的處理多個KEY的場景

 public static void main(String[] args) {
        Table<String, String, Integer> table = HashBasedTable.create();
        table.put("wudy","語文", 100);
        table.put("wudy","數(shù)學(xué)", 80);
        table.put("wudy","英語", 90);
        table.put("wudy","計(jì)算機(jī)", 89);
        table.put("peter","地理", 13);
        table.put("peter","計(jì)算機(jī)", 73);

        //最小單位cell
        Set<Table.Cell<String, String, Integer>> set = table.cellSet();
        for (Table.Cell cell:set){
            System.out.println(cell.getRowKey() + "," + cell.getColumnKey() + "," + cell.getValue());
        }

        //row set
        Set<String> rowSet = table.rowKeySet();
        System.out.println(rowSet); // [wudy, peter]

        //column set
        Set<String> columnSet = table.columnKeySet();
        System.out.println(columnSet); // [數(shù)學(xué), 語文, 英語, 計(jì)算機(jī), 地理]

        //根據(jù)rowKey獲取信息Map<column, value>
        System.out.println(table.row("wudy")); // {數(shù)學(xué)=80, 語文=100, 英語=90, 計(jì)算機(jī)=89}

        //根據(jù)column獲得信息Map<row, value>
        System.out.println(table.column("計(jì)算機(jī)")); // {wudy=89, peter=73}

    }
  • 8.函數(shù)式編程:Functions
public static void main(String[] args) {
        ArrayList<String> list = Lists.newArrayList("wudy.yu", "peter.li", "jack");
        Function<String, String> f1 = new Function<String, String>(){
            @Override
            public String apply(@Nullable String s) {
                return s.length() <= 5 ? s : s.substring(0,5);
            }
        };
        
        Function<String, String> f2 = new Function<String, String>() {
            @Nullable
            @Override
            public String apply(@Nullable String s) {
                return s.toUpperCase();
            }
        };
        Function<String, String> f3 = Functions.compose(f1, f2);
        Collection<String> collection = Collections2.transform(list, f3);
        for (String s:collection){
            System.out.println(s);
        }

    }

輸出:
WUDY.
PETER
JACK

image.png

上面的代碼是為了完成將List集合中的元素,先截取5個長度,然后轉(zhuǎn)成大寫。
函數(shù)式編程的好處在于在集合遍歷操作中提供自定義Function的操作,比如transform轉(zhuǎn)換。我們再也不需要一遍遍的遍歷集合,顯著的簡化了代碼!

  • 9.斷言Predicate

Predicate最常用的功能就是運(yùn)用在集合的過濾當(dāng)中!

image.png

public static void main(String[] args) {
// 需要注意的是Lists并沒有提供filter方法,不過你可以使用Collections2.filter完成!
        List<String> list = Lists.newArrayList("wudy.yu", "peter.li", "moom");

        Collection<String> collection = Collections2.filter(list, new Predicate<String>() {
            @Override
            public boolean apply(@Nullable String s) {
                return new StringBuilder(s).reverse().toString().equals(s);
            }
        });

        for (String s:collection) {
            System.out.println(s); // moom
        }
    }
  • 10.check null and other:Optional、Preconditions

guava中,對于null的處理手段是快速失敗,你可以看看guava的源碼,很多方法的第一行就是:Preconditions.checkNotNull(elements);
要知道null是模糊的概念,是成功呢,還是失敗呢,還是別的什么含義呢?

public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        test("null", 101, null);
    }

    public static void test(String name, Integer age, Map<String, String> extraInfo) {
        Preconditions.checkNotNull(name, "name must be given");
        Preconditions.checkArgument(age >= 18, "未成年人不能觀看");

        Map<String, String> defaultExtraInfo = Maps.newHashMap();
        defaultExtraInfo.put("name", "wudy");
        extraInfo = Optional.fromNullable(extraInfo).or(defaultExtraInfo); // java API方式: Optional.ofNullable(extraInfo).orElse(defaultExtraInfo);

        for (Map.Entry<String, String> entry : extraInfo.entrySet()){
            System.out.println(entry.getKey() + ":" + entry.getValue());  // name:wudy
        }
    }
  • 11.Guava RateLimiter
    參考文章: https://mp.weixin.qq.com/s?__biz=MzI3ODcxMzQzMw==&mid=2247546330&idx=2&sn=864bf29bb10748f34be380cfcdd63f83&chksm=eb50b0ecdc2739fa9fd4d2241d74b3f516273944d64ef22d46e20bce0b877660499b7a827430&mpshare=1&scene=23&srcid=1014KCFaEZRo7IYKNhPsA5P0&sharer_sharetime=1634185620678&sharer_shareid=f770d25bc57f1c2f9159f85750f854dc#rd

    1. Guava騷操作
      參考文章:https://mp.weixin.qq.com/s?__biz=MzUzMTA2NTU2Ng==&mid=2247572229&idx=1&sn=e82470244be0bfa059a7efd34a9f3772&chksm=fa4ba4b4cd3c2da2819c28ddaa37493e8aa3ebf5733e3cdb03269f4e017ead8210b222c5b546&mpshare=1&scene=23&srcid=0509HUFL13l1c6FKdSFePdnv&sharer_sharetime=1683621223963&sharer_shareid=7fec9c1809ccb850bfdebba7d4f7a81e#rd
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容