java基礎(chǔ)-guava集合(二)

如果你需要在不可變集合中使用 null,請使用 JDK 中的 Collections.unmodifiableXXX 方法

  • ImmutableSet

http://wiki.jikexueyuan.com/project/google-guava-official-tutorial/immutable-collections.html
https://www.yiibai.com/guava/guava_collections_utilities.html

package com.byedbl.common.collect;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.junit.Test;

import java.util.Collections;
import java.util.Set;

import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;

public class ImmutableSetTest {


    @Test
    public void testCreation_oneDuplicate() {
        // now we'll get the varargs overload
        ImmutableSet<String> set =
                ImmutableSet.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "a");
        assertEquals(
                Lists.newArrayList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"),
                Lists.newArrayList(set));
    }

    @Test
    public void testCreation_manyDuplicates() {
        // now we'll get the varargs overload
        ImmutableSet<String> set =
                ImmutableSet.of("a", "b", "c", "c", "c", "c", "b", "b", "a", "a", "c", "c", "c", "a");
        assertThat(set).containsExactly("a", "b", "c").inOrder();
    }
    @Test
    public void testCreation_arrayOfArray() {
        String[] array = new String[] {"a","b","b"};
        Set<String[]> set = ImmutableSet.<String[]>of(array);
        assertEquals(Collections.singleton(array), set);
    }

    @Test
    public void testCreation_Builder() {
        Set<String> set = ImmutableSet.<String>builder().add("a").add("b").build();
        assertEquals(Sets.newHashSet("a","b"),set);
    }

    @Test
    public void testCreation_SortedSet() {
        ImmutableSortedSet<String> set = ImmutableSortedSet.of("a", "b", "c", "a", "d", "b");
        set.asList().forEach(System.out::println);
    }

}

Multiset 繼承自Collection 而非 Set接口,所以其可以包含重復(fù)元素

可以用兩種方式看待 Multiset:

  • 沒有元素順序限制的 ArrayList
  • Map<E, Integer>,鍵為元素,值為計數(shù)
package com.byedbl.common.collect;

import com.google.common.collect.Multiset;
import com.google.common.collect.Sets;
import com.google.common.collect.TreeMultiset;
import org.junit.Test;

import java.util.Arrays;
import java.util.Set;

import static org.junit.Assert.assertEquals;

public class MultisetsTest {

//    @Test
//    public void testNewTreeMultisetDerived() {
//        TreeMultiset<DerivedComparable> set = TreeMultiset.create();
//        assertTrue(set.isEmpty());
//        set.add(new DerivedComparable("foo"), 2);
//        set.add(new DerivedComparable("bar"), 3);
//        assertThat(set)
//                .containsExactly(
//                        new DerivedComparable("bar"),
//                        new DerivedComparable("bar"),
//                        new DerivedComparable("bar"),
//                        new DerivedComparable("foo"),
//                        new DerivedComparable("foo"))
//                .inOrder();
//    }


    /**
     * 初始化Set值
     * @return :
     */
    private TreeMultiset<String> getSet() {
        TreeMultiset<String> set = TreeMultiset.create();
        set.add("foo", 2);
        set.add("bar", 3);
        set.addAll(Arrays.asList("a", "a", "b", "b"));
        return set;
    }

    @Test
    public void testTreeMultiSetSize() {
        TreeMultiset<String> set = getSet();
        // 統(tǒng)計Set中總個數(shù)9個,包含重復(fù)的個數(shù)
        assertEquals(9,set.size());
    }

    @Test
    public void testTreeMultiSetCount() {
        TreeMultiset<String> set = getSet();
        //取出指定元素的個數(shù)
        assertEquals(2,set.count("foo"));
    }

    @Test
    public void testTreeMultiSetElementSet() {
        Set<String> treeSet = Sets.newTreeSet();
        treeSet.addAll(Arrays.asList("a",  "bar", "foo","b"));
        TreeMultiset<String> set = getSet();
//        set.elementSet().forEach(System.out::println);
        //返回不重復(fù)的兩個元素
        assertEquals(treeSet,set.elementSet());
    }

    @Test
    public void testTreeMultiSetElementSetSize() {
        TreeMultiset<String> set = getSet();
        //不重復(fù)元素的個數(shù)
        assertEquals(4,set.elementSet().size());
    }

    @Test
    public void testTreeMultiSetEntrySet() {
        TreeMultiset<String> set = getSet();
        Set<Multiset.Entry<String>> entries = set.entrySet();
        //遍歷取出集合中的元素
        entries.forEach(entry-> System.out.println(entry.getElement()+" : "+ entry.getCount()));
    }

    @Test
    public void testTreeMultiSetAdd() {
        //增加給定元素在 Multiset 中的計數(shù)
        TreeMultiset<String> set = getSet();
        set.add("foo", 3);
        assertEquals(5,set.count("foo"));
    }

    @Test
    public void testTreeMultiSetRemove() {
        TreeMultiset<String> set = getSet();
        set.remove("foo", 1);
        assertEquals(1,set.count("foo"));
    }

    @Test
    public void testTreeMultiSetSetCount() {
        TreeMultiset<String> set = getSet();
        set.setCount("foo", 5);
        assertEquals(5,set.count("foo"));
    }

}

Map<K, List>或 Map<K, Set> Multimap 是把鍵映射到任意多個值的一般方式
ListMultimap.get(key)返回 List,SetMultimap.get(key)返回 Set。

image.png

*LinkedListMultimap.entries()保留了所有鍵和值的迭代順序。詳情見 doc 鏈接。
**LinkedHashMultimap 保留了映射項的插入順序,包括鍵插入的順序,以及鍵映射的所有值的插入順序。

package com.byedbl.common.collect;

import com.google.common.collect.*;
import org.junit.Test;

import java.util.Collection;
import java.util.Map;
import java.util.Set;

import static org.junit.Assert.*;

public class MultimapTest {

    private Multimap<String, String> getMultimap() {
        Multimap<String,String> multimap = HashMultimap.create();
        multimap.putAll("foo", Sets.newHashSet("foo1", "foo2"));
        multimap.putAll("bar", Sets.newHashSet("bar1", "bar2"));
        multimap.put("test", "a");
        multimap.put("test", "b");
        return multimap;
    }

    @Test
    public void testMultimap() {
        Multimap<String, String> multimap = getMultimap();
        //遍歷打印結(jié)果
//        test : [a, b]
//        foo : [foo2, foo1]
//        bar : [bar1, bar2]
        printMap(multimap);
    }

    private void printMap(Multimap<String, String> multimap) {
        multimap.asMap().forEach((k,v)-> System.out.println(k + " : "+ v));
    }

    @Test
    public void testMultimapSize() {
        Multimap<String, String> multimap = getMultimap();
        assertEquals(6, multimap.size());
        //Set<K>
        assertEquals(3,multimap.keySet().size());
        //Multiset<K>
        assertEquals(6,multimap.keys().size());
        //Collection<V>
        assertEquals(6,multimap.values().size());
        //Collection<Entry<K, V>>
        assertEquals(6,multimap.entries().size());
        //Map<K, Collection<V>>
        assertEquals(3,multimap.asMap().size());
    }

    @Test
    public void testMultimapRemove(){
        Multimap<String, String> multimap = getMultimap();
        //刪除指定元素
        assertTrue(multimap.get("foo").remove("foo2"));
        assertTrue(multimap.remove("test","a"));
        printMap(multimap);
    }

    @Test
    public void testMultimapRemoveAll() {
        Multimap<String, String> multimap = getMultimap();
        //清除鍵對應(yīng)的所有值,返回的集合包含所有之前映射到 K 的值,
        // 但修改這個集合就不會影響 Multimap 了。
        //multimap.get(key).clear()
        assertArrayEquals(multimap.removeAll("foo").toArray(),new String[]{"foo2","foo1"});
    }

    @Test
    public void testMultimapReplaceValues() {
        Multimap<String, String> multimap = getMultimap();
        //清除鍵對應(yīng)的所有值,并重新把 key 關(guān)聯(lián)到 Iterable 中的每個元素。
        // 返回的集合包含所有之前映射到 K 的值。
        multimap.replaceValues("foo", Lists.newArrayList("foo3", "foo4"));
        assertArrayEquals(multimap.get("foo").toArray(),new String[]{"foo3", "foo4"});
        printMap(multimap);
    }

    @Test
    public void testMultimapEntries() {
        Multimap<String, String> multimap = getMultimap();
        Collection<Map.Entry<String, String>> entries = multimap.entries();
        //遍歷key和values值
        entries.forEach(entry-> System.out.println(entry.getKey()+" : " + entry.getValue()));
    }

    @Test
    public void testMultimapKeySet() {
        Multimap<String, String> multimap = getMultimap();
        Set<String> set = multimap.keySet();
        assertEquals(set,Sets.newHashSet("test","bar","foo"));
        set.forEach(System.out::println);
    }

    @Test
    public void testMultimapValues() {
        Multimap<String, String> multimap = getMultimap();
        Collection<String> collection = multimap.values();
        // multimap.values() 就是一個 集合
        collection.forEach(System.out::println);
        System.out.println("====================");
        //asMap().values() 是按照鍵值分開的集合
//        [a, b]
//        [foo2, foo1]
//        [bar1, bar2]
        Collection<Collection<String>> values = multimap.asMap().values();
        values.forEach(System.out::println);
    }



}

實現(xiàn)鍵值對的雙向映射,解決傳統(tǒng)的維護兩個HashMap經(jīng)常出現(xiàn)的問題

BiMap<K, V>是特殊的 Map:

  • 可以用 inverse()反轉(zhuǎn) BiMap<K, V>的鍵值映射
  • 保證值是唯一的,因此 values()返回 Set 而不是普通的 Collection

BiMap在鍵和值是唯一的時候很有用,可以隨意反轉(zhuǎn)

package com.byedbl.common.collect;

import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import org.junit.Test;

public class BiMapTest {
    private BiMap<String,Integer> getBiMap() {
        BiMap<String,Integer> biMap = HashBiMap.create();
        biMap.put("語文", 60);
//        biMap.put("語文", 70);
        biMap.put("數(shù)學(xué)", 70);
        biMap.put("數(shù)學(xué)", 80);
        return biMap;
    }

    @Test
    public void testPutWithSameValueFails() {
        BiMap<String,Integer> biMap = getBiMap();
        try {
            //在 BiMap 中,如果你想把鍵映射到已經(jīng)存在的值,會拋出 IllegalArgumentException 異常
            biMap.put("語文", 80);
//            fail("Expected IllegalArgumentException");
        } catch (IllegalArgumentException expected) {
            System.out.println("expected error");
        }

    }

    @Test
    public void testReverse() {
        BiMap<String,Integer> biMap = getBiMap();
        biMap.inverse().forEach((k,v)-> {
            System.out.println(k + " " + v);
        });
    }
    @Test
    public void testForcePutWithSameValueFails() {
        BiMap<String,Integer> biMap = getBiMap();
//        try {
            //在 BiMap 中,如果你想把鍵映射到已經(jīng)存在的值,會拋出 IllegalArgumentException 異常
            //可以用forcePut替代
            biMap.forcePut("語文", 80);
//            fail("Expected IllegalArgumentException");
//        } catch (IllegalArgumentException expected) {

//        }

    }


}

解決多個鍵做索引的問題 Map<FirstName, Map<LastName, Person>>

Table 有如下幾種實現(xiàn):

  • HashBasedTable:本質(zhì)上用 HashMap<R, HashMap<C, V>>實現(xiàn);
  • TreeBasedTable:本質(zhì)上用 TreeMap<R, TreeMap<C,V>>實現(xiàn);
  • ImmutableTable:本質(zhì)上用 ImmutableMap<R, ImmutableMap<C, V>>實現(xiàn);注:ImmutableTable 對稀疏或密集的數(shù)據(jù)集都有優(yōu)化。
  • ArrayTable:要求在構(gòu)造時就指定行和列的大小,本質(zhì)上由一個二維數(shù)組實現(xiàn),以提升訪問速度和密集 Table 的內(nèi)存利用率。ArrayTable 與其他 Table 的工作原理有點不同,請參見 Javadoc 了解詳情。

package com.byedbl.common.collect;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import org.junit.Test;

import java.util.Map;
import java.util.Set;

public class TableTest {

    private Table<String, String, String> getTable() {
        Table<String, String, String> employeeTable = HashBasedTable.create();

        //initialize the table with employee details
        employeeTable.put("IBM", "101","Mahesh");
        employeeTable.put("IBM", "102","Ramesh");
        employeeTable.put("IBM", "103","Suresh");

        employeeTable.put("Microsoft", "102","Sohan");
        employeeTable.put("Microsoft", "112","Mohan");
        employeeTable.put("Microsoft", "113","Ram");

        employeeTable.put("TCS", "121","Ram");
        employeeTable.put("TCS", "122","Shyam");
        employeeTable.put("TCS", "123","Sunil");
        return employeeTable;
    }

    @Test
    public void testRow() {
        Table<String, String, String> employeeTable = getTable();
        Map<String,String> ibmEmployees =  employeeTable.row("IBM");
        System.out.println(ibmEmployees);
        ibmEmployees =  employeeTable.row("102");
        System.out.println(ibmEmployees);
        ibmEmployees =  employeeTable.column("102");
        System.out.println(ibmEmployees);

        //get all the unique keys of the table
        Set<String> employers = employeeTable.rowKeySet();
        System.out.print("Employers: ");
        for(String employer: employers){
            System.out.print(employer + " ");
        }
        System.out.println();
        System.out.println("-----------------------------");

        //get a Map corresponding to 102
        Map<String,String> EmployerMap =  employeeTable.column("102");
        for(Map.Entry<String, String> entry : EmployerMap.entrySet()){
            System.out.println("Employer: " + entry.getKey() + ", Name: " + entry.getValue());
        }

        System.out.println("-----------------------------");
        //get a Map corresponding to 102
        EmployerMap =  employeeTable.column("Ram");
        for(Map.Entry<String, String> entry : EmployerMap.entrySet()){
            System.out.println("Employer: " + entry.getKey() + ", Name: " + entry.getValue());
        }
    }

    @Test
    public void testRowMap() {
//        IBM  {101=Mahesh, 102=Ramesh, 103=Suresh}
//        Microsoft  {102=Sohan, 112=Mohan, 113=Ram}
//        TCS  {121=Ram, 122=Shyam, 123=Sunil}
        Table<String, String, String> employeeTable = getTable();
        Map<String, Map<String, String>> rowMap = employeeTable.rowMap();
        rowMap.forEach((k,v)-> System.out.println(k + "  " + v));
    }

    @Test
    public void testColumnMap() {
//        101  {IBM=Mahesh}
//        102  {IBM=Ramesh, Microsoft=Sohan}
//        103  {IBM=Suresh}
//        112  {Microsoft=Mohan}
//        113  {Microsoft=Ram}
//        121  {TCS=Ram}
//        122  {TCS=Shyam}
//        123  {TCS=Sunil}

        Table<String, String, String> employeeTable = getTable();
        Map<String, Map<String, String>> columnMap = employeeTable.columnMap();
        columnMap.forEach((k,v)-> System.out.println(k + "  " + v));
    }

    @Test
    public void testCellSet() {
        Table<String, String, String> employeeTable = getTable();
        Set<Table.Cell<String, String, String>> cells = employeeTable.cellSet();
        cells.forEach(c-> System.out.println(c.getRowKey() + " " + c.getColumnKey()+ " " + c.getValue()));
    }
}

傳入三個值,row,column,value;既可以用row獲取,也可以用columnKey獲取值.遍歷用cellSet

  • ClassToInstanceMap

特殊的Map,它的鍵是類型,而值是符合鍵所指類型的對象

package com.byedbl.common.collect;

import com.google.common.collect.ClassToInstanceMap;
import com.google.common.collect.MutableClassToInstanceMap;
import org.junit.Test;

public class ClassToInstanceMapTest {

    @Test
    public void testClassToInstanceMap() {
        ClassToInstanceMap<Number> numberDefaults= MutableClassToInstanceMap.create();
        for(int i=0;i<10;i++) {
            numberDefaults.putInstance(Integer.class, i);
            numberDefaults.putInstance(Long.class, (long) i);
        }
        Integer instance = numberDefaults.getInstance(Integer.class);
        //9
        System.out.println(instance);
        System.out.println(numberDefaults.getInstance(Long.class));
    }
}

存放類型與其對應(yīng)的值,后面的會覆蓋前面的,

  • RangeSet

區(qū)間,描述了一組不相連的、非空的區(qū)間。當(dāng)把一個區(qū)間添加到可變的RangeSet時,所有相連的區(qū)間會被合并,空區(qū)間會被忽略

package com.byedbl.common.collect;

import com.google.common.collect.Range;
import com.google.common.collect.RangeSet;
import com.google.common.collect.TreeRangeSet;
import org.junit.Test;

public class RangeSetTest {

    @Test
    public void testRangeSet() {
        RangeSet<Integer> rangeSet = TreeRangeSet.create();
        rangeSet.add(Range.closed(1, 10)); // {[1,10]}
        rangeSet.add(Range.closedOpen(11, 15));//不相連區(qū)間:{[1,10], [11,15)}
        rangeSet.add(Range.closedOpen(15, 20)); //相連區(qū)間; {[1,10], [11,20)}
        rangeSet.add(Range.openClosed(0, 0)); //空區(qū)間; {[1,10], [11,20)}
        rangeSet.remove(Range.open(5, 10)); //分割[1, 10]; 結(jié)果為{[1,5], [10,10], [11,20)}
        System.out.println(rangeSet);
    }
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,428評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,024評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,285評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,548評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,328評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,878評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,971評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,098評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,616評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,554評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,725評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,243評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 43,971評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,361評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,613評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,339評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,695評論 2 370

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

  • com.google.common.collect 1、不可變集合 何為“不可變” 無法修改返回容器的內(nèi)容,注意,...
    拾壹北閱讀 2,606評論 0 4
  • 不可變集合類 為什么要使用不可變集合不可變對象有很多優(yōu)點,包括: 當(dāng)對象被不可信的庫調(diào)用時,不可變形式是安全的;不...
    icecrea閱讀 1,630評論 0 0
  • Guava簡單介紹 1 資料鏈接 極客學(xué)院http://wiki.jikexueyuan.com/project/...
    田園小丁閱讀 1,851評論 0 3
  • 作者:李碩 秋天,一片片黃葉從樹梢落下,被風(fēng)吹著,在空中悠悠地飄, 黃昏吹著風(fēng)的軟,細(xì)雨點灑在花前。 這一路走來,...
    濰科WK閱讀 462評論 0 0
  • 遇見你 年輪已裂成兩半 造物主的心事 流落在掌間 據(jù)說你是印度的主 虛構(gòu)一場歷劫 抵達(dá)神靈的眉心 高高在上,日夜誦...
    客塵人閱讀 177評論 3 4