【三方包系列】倚天劍:apache-common-collections

接著上次的話題,再介紹apache-common系列中另一個(gè)重要的成員:apache-common-collections。包中對(duì)Java中的集合類進(jìn)行了一定的補(bǔ)充斤寇,定義了一些全新的集合棉饶,當(dāng)然也是實(shí)現(xiàn)了Collection接口的,比如Bag赁咙,BidiMap钮莲。同時(shí)擁有新版本的原有集合,比如FastArrayList彼水。最后崔拥,更為重要的是一系列utils類,提供了我們常用的集合操作凤覆,可以大大方便我們的日常編程链瓦。

用apache-common-collections極大提升代碼可讀性和開發(fā)速度,實(shí)為武器中的倚天劍。

天下武功慈俯,唯快不破

我們也根據(jù)包的內(nèi)容分為四塊渤刃,

  • 新的集合
  • 新的概念
  • 新版本的老集合
  • 有用的工具類

下面就開始:

新的集合

Bag

Bag定義了一種集合:收集一個(gè)對(duì)象出現(xiàn)的次數(shù)。
例如Bag:{a,a,b,c}
調(diào)用bag.getCount(a)返回2贴膘,意味著里面有2個(gè)a卖子。
調(diào)用bag.uniqueSet()則返回一個(gè)set,值為{a,b,c}刑峡。

這個(gè)集合可以用來計(jì)數(shù)洋闽,而如果用set則無法實(shí)現(xiàn),用map可以把count作為value來勉強(qiáng)實(shí)現(xiàn)突梦,但顯然在add操作的時(shí)候并不優(yōu)雅诫舅,需要:

map.put(key,map.get(key)+1);

并且還需要擔(dān)心map中存的不是一個(gè)整數(shù)。
用Bag計(jì)算森林中的兔子:

HashBag bag = new HashBag();
bag.add("rabbit",1);
bag.add("fox",1);
bag.add("rabbit",2);

//rabbit count
System.out.print(bag.getCount("rabbit"));
//how many animals
System.out.print(bag.uniqueSet().size());

除了HashBag宫患,還有SynchronizedBag,TreeBag,可以通過源碼或者javadoc進(jìn)一步了解使用骚勘。

BidiMap

BidiMap定義了一種map,不僅可以通過key得到value撮奏,還可以通過value得到key俏讹。Bidi意思是bidirectional,雙向使用的map畜吊。
除了傳統(tǒng)map的操作泽疆,特殊操作如下:

BidiMap bidi = new DualHashBidiMap();
bidi.put("k1","v1");
bidi.put("k2","v2");

bidi.get("k2"); // return v2
bidi.getKey("v2"); // return k2

bidi.inverseBidiMap(); //反轉(zhuǎn)bidi,原先的value作為key

作為代價(jià)玲献,BidiMap必須要求k和v是一一對(duì)應(yīng)的殉疼,在上述代碼之后,無法做到bidi.put("k2","v1");捌年,因?yàn)檫@樣就無法實(shí)現(xiàn)響應(yīng)操作瓢娜。
現(xiàn)實(shí)中如學(xué)號(hào)和身份證號(hào)做對(duì)應(yīng)就是這樣一種關(guān)系,可以視情況使用礼预。

除了DualHashBidiMap眠砾,還有TreeBidiMap等,可以通過源碼或者javadoc進(jìn)一步了解使用。

新的概念

Predicate 預(yù)言

這個(gè)類主要結(jié)合CollectionUtils.find,CollectionUtils.filter來使用托酸。
他的作用類似于『斷言』褒颈,其中只有一個(gè)方法:

public boolean evaluate(Object object);

這個(gè)方法用于判斷一個(gè)對(duì)象是否滿足某種標(biāo)準(zhǔn),你可以通過讓age>50來尋找列表中年齡大于50的元素励堡,或是找到id為12306的那個(gè)對(duì)象谷丸,如

Predicate predicate = new Predicate{
  @override
  public boolean evaluate(Object object){
    return PropertyUtils.getSimpleProperty(object,"age") >50 ;
  }
}
Predicate predicate2 = new Predicate{
  @override
  public boolean evaluate(Object object){
    return PropertyUtils.getSimpleProperty(object,"id") == 12306 ;
  }
}
//刪除不滿足條件的結(jié)果
CollectionUtils.filter(list,predicate);
//返回第一個(gè)滿足的元素
Object obj = CollectionUtils.find(list,predicate2);

同時(shí),Predicate可以進(jìn)行謂詞連接应结,借助于:

  • AndPredicate
  • OrPredicate
  • AnyPredicate
  • NotPredicate
    我們可以創(chuàng)造出id為12306并且年齡大于50的預(yù)言
new AndPredicate(predicate1,predicate2);

代碼的復(fù)用程度被極大提升,這個(gè)類是apache-common包最精髓之處刨疼。

Closure和Transformer 代碼閉包

介紹這兩個(gè)接口主要目的是擴(kuò)大思路,因?yàn)殡S著jdk8的引入,作者認(rèn)為這兩個(gè)接口的作用性就有待商榷了揩慕。但是在他們引入的時(shí)候游两,這個(gè)思路無疑是值得參考的。
我們從一段代碼來了解這兩個(gè)類漩绵。

//傳統(tǒng)代碼
..do something
for(obj in list){
  obj.sayHello();
}
..do otherthing

//使用closure
Closure closure = ClosureUtils.invokerClosure("sayHello");

..do something
CollectionUtils.forAllDo(list,closure);
..do otherthing

沒錯(cuò)贱案,這就是jdk8中大力引入的函數(shù)式編程思想。在其他語言(javascript, scala, python等)高度動(dòng)態(tài)性的影響下止吐,開發(fā)者們意識(shí)到函數(shù)式編程的好處宝踪。
最大好處在于減少了代碼塊的層次,把for碍扔,if瘩燥,swith,while等等的嵌套代碼結(jié)構(gòu)更改為了順序型的結(jié)構(gòu)不同,讓代碼可讀性大大提升厉膀。實(shí)際上作者自己的感觸也是這樣的,一段長代碼的難懂程度跟嵌套代碼的深度成正比二拐。

想像一下:

for(condition){
  if(cond2){
    if(cond4){
      ..do trunk logic
    }else{
      ..do branch logic
    }
  }else{
    if(cond3){
      ..do fast fail logic
    }
    ..do error fixing logic
  }
}

講到這里服鹅,可以正式介紹一下Closure和Transformer。他們的含義是封裝一個(gè)代碼結(jié)構(gòu)塊百新,前者是void函數(shù)企软,后者是有返回值的函數(shù),可以理解為對(duì)一個(gè)對(duì)象的transform饭望。
jdk8中正式引入了lambda功能仗哨,我們的解決方案可以是:

//forEach函數(shù)實(shí)現(xiàn)內(nèi)部迭代
list.forEach(o->{System.out.println(o);});

這里想說的是,技術(shù)多種多樣铅辞,思想不變

老集合的新面孔

這一節(jié)我會(huì)走馬觀花的列舉一系列類厌漂,具體使用可以自行發(fā)掘。

  • GrowthList
    為了避免大部分IndexOutOfBoundsException而使用的list容器斟珊。對(duì)于index越界會(huì)安靜的處理:超過length的set和add操作會(huì)自動(dòng)增大list以適應(yīng)苇倡。

  • LazyList
    通過傳入一個(gè)factory對(duì)象來實(shí)現(xiàn)懶加載。同時(shí)也具有Growth的特點(diǎn)倍宾,比如get一個(gè)不存在的index時(shí)雏节,會(huì)自動(dòng)create一個(gè)對(duì)象并返回胜嗓。

[1,2,3].get(5)會(huì)導(dǎo)致:[1,2,3,null,factory.create()]
  • SetUniqueList
    內(nèi)部是一個(gè)set的list高职,我們經(jīng)常需要用到?jīng)]有重復(fù)的列表,會(huì)新建一個(gè)ArrayList辞州,并最后調(diào)用
    new ArrayList(new HashSet(list))來去重怔锌。而這個(gè)類會(huì)自動(dòng)幫你做好這些。

  • SynchronizedList
    一個(gè)線程安全的列表

  • LazyMap
    類似LazyList

  • LRUMap
    一個(gè)有限個(gè)數(shù)的Map,并根據(jù)LRU算法來決定哪些元素被丟棄埃元,適合用來做簡易緩存涝涤。

  • MultiKeyMap
    多個(gè)鍵的Map,譬如操作班級(jí)岛杀,學(xué)號(hào)時(shí):

map.put("class1",1001,john);

但看過源碼之后發(fā)現(xiàn)是通過合并多個(gè)key的hashcode來做到這一點(diǎn)阔拳,那么和我們使用普通map時(shí)直接put("class1"+1001,john)效果類似。只能理解為提升代碼可讀性了类嗤。

  • MultiValueMap
    這個(gè)類可以方便的為一個(gè)key對(duì)應(yīng)多個(gè)value的情況做適應(yīng)糊肠。
    然而如果了解Google的Guava包,實(shí)際上里面有一個(gè)更好用的類:Multimap這里就不過多介紹了遗锣。

  • CompositeCollection
    包括CompositeSet,CompositeMap货裹,用于保持其他容器的同時(shí)提供各容器混合的功能。

以CompositeSet為例精偿,
compositeSet.add(set1,set2);
形成了一個(gè)二級(jí)的set弧圆,這一點(diǎn)和set1.addAll(set2)是不一樣的,使用時(shí)我們可以同時(shí)存在set1,set2和compositeSet。
而對(duì)二級(jí)set的修改操作會(huì)直接影響到子容器笔咽。
compositeSet.remove(obj);
如果set1和set2都包含了obj搔预,會(huì)同時(shí)刪去obj。

有用的工具類

這是collections包中最有價(jià)值的一個(gè)部分叶组,我準(zhǔn)備介紹ListUtilsCollectionUtils斯撮。

ListUtils 列表工具類
  • ListUtils.intersection(list1,list2)
    取交集
  • ListUtils.subtract(list1,list2)
    返回list1和list2的差。這里和list1.removeAll(list2)的差別在于:
    • 前者不改變?nèi)魏我粋€(gè)集合
    • 如果list1中有2個(gè)a扶叉,list2中有一個(gè)a:removeAll會(huì)將list1中所有的a都抹去勿锅,而subtract結(jié)果list1仍然會(huì)剩下一個(gè)a
  • ListUtils.union(list1,list2)
    取并集
  • ListUtils.removeAll(list1,list2)
    不改變list的情況下做removeAll
CollectionUtils 通用的集合工具類
  • CollectionUtils.union(c1,c2),CollectionUtils.intersection(c1,c2)
    不再解釋
  • CollectionUtils.disjunction(c1,c2)
    返回兩者的不相交部分的并集枣氧,沒想到一個(gè)現(xiàn)實(shí)場景溢十。。
  • CollectionUtils.containsAny(c1,c2)
    只要c1包含任何一個(gè)c2的元素达吞,返回true

前方高能

  • CollectionUtils.find(c,predicate)
    重要方法:借助Predicate達(dá)到神一般的效果张弛,從此減少一半for循環(huán)。返回第一個(gè)找到的元素

  • CollectionUtils.filter(c,predicate)
    重要方法:同上酪劫,直接改變?nèi)萜鱟吞鸭。

  • CollectionUtils.transform(c,transformer)
    重要方法:還是神器,但是在jdk8中等同于foreach方法效果覆糟。如果jdk<8刻剥,可以用這個(gè)方法代替

  • CollectionUtils.countMatches(c,predicate)
    根據(jù)predicate返回有多少元素滿足預(yù)言,返回值int滩字。

  • CollectionUtils.select(c,predicate)
    根據(jù)predicate找出滿足的元素造虏,組成新的collection并返回

  • CollectionUtils.select(c,predicate,outputCollection)
    根據(jù)predicate找出滿足的元素御吞,加入到outputCollection中。

  • CollectionUtils.isEmpty(c)
    簡單實(shí)用漓藕,是否為null或者空集合

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末陶珠,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子享钞,更是在濱河造成了極大的恐慌揍诽,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件栗竖,死亡現(xiàn)場離奇詭異寝姿,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)划滋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門饵筑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人处坪,你說我怎么就攤上這事根资。” “怎么了同窘?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵玄帕,是天一觀的道長。 經(jīng)常有香客問我想邦,道長裤纹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任丧没,我火速辦了婚禮鹰椒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘呕童。我一直安慰自己漆际,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布夺饲。 她就那樣靜靜地躺著奸汇,像睡著了一般。 火紅的嫁衣襯著肌膚如雪往声。 梳的紋絲不亂的頭發(fā)上擂找,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音浩销,去河邊找鬼贯涎。 笑死,一個(gè)胖子當(dāng)著我的面吹牛撼嗓,可吹牛的內(nèi)容都是我干的柬采。 我是一名探鬼主播欢唾,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼且警,長吁一口氣:“原來是場噩夢啊……” “哼粉捻!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起斑芜,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤肩刃,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后杏头,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盈包,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年醇王,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了呢燥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡寓娩,死狀恐怖叛氨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情棘伴,我是刑警寧澤寞埠,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站焊夸,受9級(jí)特大地震影響仁连,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜阱穗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一饭冬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧揪阶,春花似錦伍伤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蕴茴,卻和暖如春劝评,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背倦淀。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國打工蒋畜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人撞叽。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓姻成,卻偏偏與公主長得像插龄,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子科展,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

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