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實例總是不可變的势誊。用來定義joiner目標語義的配置方法總會返回一個新的joiner實例。這使得joiner實例都是線程安全的谣蠢,你可以將其定義為static final常量
  • 2.guava對JDK提供的原生類型操作進行了擴展
 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ù)類型的擴展支持

  • 3.對JDK集合的有效補充

灰色地帶:Multiset
JDK的集合粟耻,提供了有序且可以重復(fù)的List,無序且不可以重復(fù)的Set眉踱。那這里其實對于集合涉及到了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琼牧,我猜的,哈哈)
重點: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的缺陷了嗎巨坊?
實際上,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,保護性拷貝)
        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是一個鍵,一個值攻人,一對一的取试,那么在實際開發(fā)中,顯然存在一個KEY多個VALUE的情況(比如一個分類下的書本)怀吻,我們往往這樣表達:Map<k,List>瞬浓,好像有點臃腫!臃腫也就算了蓬坡,更加不爽的事猿棉,我們還得判斷KEY是否存在來決定是否new 一個LIST出來,有點麻煩渣窜!更加麻煩的事情還在后頭铺根,比如遍歷宪躯,比如刪除

 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的實現(xiàn)類有:ArrayListMultimap/HashMultimap/LinkedHashMultimap/TreeMultimap/ImmutableMultimap

  • 6.雙向BiMap

JDK提供的MAP讓我們可以find value by key,那么能不能通過find key by value呢坝橡,能不能KEYVALUE都是唯一的呢泻帮。這是一個雙向的概念,即forward+backward计寇。
在實際場景中有這樣的需求嗎锣杂?比如通過用戶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

        // 強制覆蓋
        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的源碼實現(xiàn)踱蠢,實際上,當(dāng)你創(chuàng)建BiMap的時候棋电,在內(nèi)部維護了2個map茎截,一個forward map,一個backward map赶盔,并且設(shè)置了它們之間的關(guān)系企锌。
因此,biMap.inverse() != biMap于未;biMap.inverse().inverse() == biMap

  • 7.多個keyTable

我們知道數(shù)據(jù)庫除了主鍵外霎俩,還提供了復(fù)合索引,而且實際中這樣的多級關(guān)系查找也是比較多的沉眶,當(dāng)然我們可以利用嵌套的Map來實現(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","計算機", 89);
        table.put("peter","地理", 13);
        table.put("peter","計算機", 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ù)rowKey獲取信息Map<column, value>
        System.out.println(table.row("wudy")); // {數(shù)學(xué)=80, 語文=100, 英語=90, 計算機=89}

        //根據(jù)column獲得信息Map<row, value>
        System.out.println(table.column("計算機")); // {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最常用的功能就是運用在集合的過濾當(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)系作者
  • 序言:七十年代末禽绪,一起剝皮案震驚了整個濱河市蓖救,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌印屁,老刑警劉巖藻糖,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異库车,居然都是意外死亡巨柒,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門柠衍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來洋满,“玉大人,你說我怎么就攤上這事。” “怎么了冰评?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長驻民。 經(jīng)常有香客問我,道長履怯,這世上最難降的妖魔是什么回还? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮叹洲,結(jié)果婚禮上柠硕,老公的妹妹穿的比我還像新娘。我一直安慰自己运提,他們只是感情好蝗柔,可當(dāng)我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著民泵,像睡著了一般癣丧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上栈妆,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天胁编,我揣著相機與錄音厢钧,去河邊找鬼。 笑死掏呼,一個胖子當(dāng)著我的面吹牛坏快,可吹牛的內(nèi)容都是我干的铅檩。 我是一名探鬼主播憎夷,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼昧旨!你這毒婦竟也來了拾给?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤兔沃,失蹤者是張志新(化名)和其女友劉穎蒋得,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乒疏,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡额衙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了怕吴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片窍侧。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖转绷,靈堂內(nèi)的尸體忽然破棺而出伟件,到底是詐尸還是另有隱情,我是刑警寧澤议经,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布斧账,位于F島的核電站,受9級特大地震影響煞肾,放射性物質(zhì)發(fā)生泄漏咧织。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一籍救、第九天 我趴在偏房一處隱蔽的房頂上張望拯爽。 院中可真熱鬧,春花似錦钧忽、人聲如沸毯炮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽桃煎。三九已至,卻和暖如春大刊,著一層夾襖步出監(jiān)牢的瞬間为迈,已是汗流浹背三椿。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留葫辐,地道東北人搜锰。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像耿战,于是被迫代替她去往敵國和親蛋叼。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內(nèi)容