天天看點

Guava學習筆記:Guava新集合-Table等

Guava庫新集合的Table,ClassToInstanceMap,RangeSet,RangeMap等

  Table

  當我們需要多個索引的資料結構的時候,通常情況下,我們隻能用這種醜陋的Map<FirstName, Map<LastName, Person>>來實作。為此Guava提供了一個新的集合類型-Table集合類型,來支援這種資料結構的使用場景。Table支援“row”和“column”,而且提供多種視圖。 

@Test
    public void TableTest(){
        Table<String, Integer, String> aTable = HashBasedTable.create();  
 
        for (char a = 'A'; a <= 'C'; ++a) {  
            for (Integer b = 1; b <= 3; ++b) {   
                aTable.put(Character.toString(a), b, String.format("%c%d", a, b));  
            }  
        }  
   
        System.out.println(aTable.column(2));  
        System.out.println(aTable.row("B"));   
        System.out.println(aTable.get("B", 2));  

        System.out.println(aTable.contains("D", 1));   
        System.out.println(aTable.containsColumn(3));   
        System.out.println(aTable.containsRow("C"));  
        System.out.println(aTable.columnMap()); 
        System.out.println(aTable.rowMap());   

        System.out.println(aTable.remove("B", 3)); 
    }      

  輸出:

{A=A2, B=B2, C=C2}
{1=B1, 2=B2, 3=B3}
B2
false
true
true
{1={A=A1, B=B1, C=C1}, 2={A=A2, B=B2, C=C2}, 3={A=A3, B=B3, C=C3}}
{A={1=A1, 2=A2, 3=A3}, B={1=B1, 2=B2, 3=B3}, C={1=C1, 2=C2, 3=C3}}
B3      

  Table視圖:

  rowMap()傳回一個Map<R, Map<C, V>>的視圖。rowKeySet()類似地傳回一個Set<R>。

  row(r)傳回一個非null的Map<C, V>。修改這個視圖Map也會導緻原表格的修改。

  和列相關的方法有columnMap(), columnKeySet()和column(c)。(基于列的操作會比基于行的操作效率差些)

  cellSet()傳回的是以Table.Cell<R, C, V>為元素的Set。這裡的Cell就類似Map.Entry,但是它是通過行和列來區分的。

  Table有以下實作:

  HashBasedTable:基于HashMap<R, HashMap<C, V>>的實作。

  TreeBasedTable:基于TreeMap<R, TreeMap<C, V>>的實作。

  ImmutableTable:基于ImmutableMap<R, ImmutableMap<C, V>>的實作。(注意,ImmutableTable已對稀疏和密集集合做了優化)

  ArrayTable:ArrayTable是一個需要在建構的時候就需要定下行列的表格。這種表格由二維數組實作,這樣可以在密集資料的表格的場合,提高時間和空間的效率。

  ClassToInstanceMap

  有的時候,你的map的key并不是一種類型,他們是很多類型,你想通過映射他們得到這種類型,guava提供了ClassToInstanceMap滿足了這個目的。

  除了繼承自Map接口,ClassToInstaceMap提供了方法 T getInstance(Class<T>) 和 T putInstance(Class<T>, T),消除了強制類型轉換。

  該類有一個簡單類型的參數,通常稱為B,代表了map控制的上層綁定,例如:

ClassToInstanceMap<Number> numberDefaults = MutableClassToInstanceMap.create();
numberDefaults.putInstance(Integer.class, Integer.valueOf(0));      

  從技術上來說,ClassToInstanceMap<B> 實作了Map<Class<? extends B>, B>,或者說,這是一個從B的子類到B對象的映射,這可能使得ClassToInstanceMap的泛型輕度混亂,但是隻要記住B總是Map的上層綁定類型,通常來說B隻是一個對象。

  guava提供了有用的實作, MutableClassToInstanceMap 和 ImmutableClassToInstanceMap.

  重點:像其他的Map<Class,Object>,ClassToInstanceMap 含有的原生類型的項目,一個原生類型和他的相應的包裝類可以映射到不同的值;

import org.junit.Test;

import com.google.common.collect.ClassToInstanceMap;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.MutableClassToInstanceMap;

public class OtherTest {
    
    @Test
    public  void ClassToInstanceMapTest() {
        ClassToInstanceMap<String> classToInstanceMapString =MutableClassToInstanceMap.create();
        ClassToInstanceMap<Person> classToInstanceMap =MutableClassToInstanceMap.create();
        Person person= new Person("peida",20);
        System.out.println("person name :"+person.name+" age:"+person.age);
        classToInstanceMapString.put(String.class, "peida");
        System.out.println("string:"+classToInstanceMapString.getInstance(String.class));
        
        classToInstanceMap.putInstance(Person.class,person);
        Person person1=classToInstanceMap.getInstance(Person.class);
        System.out.println("person1 name :"+person1.name+" age:"+person1.age);
    }
}

class Person {
    public String name;
    public int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}       

  RangeSet

  RangeSet用來處理一系列不連續,非空的range。當添加一個range到一個RangeSet之後,任何有連續的range将被自動合并,而空的range将被自動去除。例如:

@Test
    public void RangeSetTest(){
        RangeSet<Integer> rangeSet = TreeRangeSet.create();
        rangeSet.add(Range.closed(1, 10));
        System.out.println("rangeSet:"+rangeSet);
        rangeSet.add(Range.closedOpen(11, 15)); 
        System.out.println("rangeSet:"+rangeSet);
        rangeSet.add(Range.open(15, 20));
        System.out.println("rangeSet:"+rangeSet);
        rangeSet.add(Range.openClosed(0, 0)); 
        System.out.println("rangeSet:"+rangeSet);
        rangeSet.remove(Range.open(5, 10)); 
        System.out.println("rangeSet:"+rangeSet);
    }      
輸出:
rangeSet:{[1‥10]}
rangeSet:{[1‥10][11‥15)}
rangeSet:{[1‥10][11‥15)(15‥20)}
rangeSet:{[1‥10][11‥15)(15‥20)}
rangeSet:{[1‥5][10‥10][11‥15)(15‥20)}      

  注意,像合并Range.closed(1, 10)和Range.closedOpen(11, 15)這樣的情況,我們必須先用調用Range.canonical(DiscreteDomain)傳入DiscreteDomain.integers()處理一下。

  RangeSet的視圖

  RangeSet的實作支援了十分豐富的視圖,包括:

  complement():是個輔助的RangeSet,它本身就是一個RangeSet,因為它包含了非連續,非空的range。

  subRangeSet(Range<C>): 傳回的是一個交集的視圖。

  asRanges():傳回可以被疊代的Set<Range<C>>的視圖。

  asSet(DiscreteDomain<C>) (ImmutableRangeSet only):傳回一個ImmutableSortedSet<C>類型的視圖,裡面的元素是range裡面的元素,而不是range本身。(如果DiscreteDomain和RangeSet的上限或下限是無限的話,這個操作就不能支援)

  Queries

  除了支援各種視圖,RangeSet還支援各種直接的查詢操作,其中最重要的是:

  contains(C):這是RangeSet最基本的操作,它能查詢給定的元素是否在RangeSet裡。

  rangeContaining(C): 傳回包含給定的元素的Range,如果不存在就傳回null。

  encloses(Range<C>): 用來判斷給定的Range是否包含在RangeSet裡面。

  span():傳回一個包含在這個RangeSet的所有Range的并集。

  RangeMap

  RangeMap代表了非連續非空的range對應的集合。不像RangeSet,RangeMap不會合并相鄰的映射,甚至相鄰的range對應的是相同的值。例如:

@Test
    public void RangeMapTest(){
        RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
         rangeMap.put(Range.closed(1, 10), "foo"); 
         System.out.println("rangeMap:"+rangeMap);
         rangeMap.put(Range.open(3, 6), "bar"); 
         System.out.println("rangeMap:"+rangeMap);
         rangeMap.put(Range.open(10, 20), "foo"); 
         System.out.println("rangeMap:"+rangeMap);
         rangeMap.remove(Range.closed(5, 11)); 
         System.out.println("rangeMap:"+rangeMap);
    }

    輸出:
    rangeMap:[[1‥10]=foo]
    rangeMap:[[1‥3]=foo, (3‥6)=bar, [6‥10]=foo]
    rangeMap:[[1‥3]=foo, (3‥6)=bar, [6‥10]=foo, (10‥20)=foo]
    rangeMap:[[1‥3]=foo, (3‥5)=bar, (11‥20)=foo]      

  RangeMap的視圖

  RangeMap提供了兩種視圖:

  asMapOfRanges():傳回Map<Range<K>, V>類型的視圖。這個操作可以被用作疊代操作。

  subRangeMap(Range<K>)提供給定Range的交集。這個操作可以推廣到傳統的headMap, subMap, 和tailMap。

關注公衆号:架構未來 ,我們一起學習成長

Guava學習筆記:Guava新集合-Table等