帶你領略 Google Collections 1

原貼地址:

http://jubin2002.javaeye.com/blog/471661

 

 

    Java的集合框架是Java類庫當中使用頻率最高的部分之一,Google公司發起了一個項目,用來擴展Java的集合框架,提供一些高級的集合操作API。

http://code.google.com/p/google-collections/

這個項目叫做Google Collection,託管在Google Code上面,它必須使用JDK5.0以上的版本

 

下面,讓我帶你領略下這個項目的優雅之處吧

 

1,Immutable Collections

 

什麼是Immutable?

 

    Immutable是不可改變的意思。

 

    在JDK中有Collections.unmodifiableFoo()來轉換,不過他們之間依然有區別。 Collections.unmodifiableFoo()只是原集合的一個視圖,在這個視圖層面無法修改,但當原集合發生改變時,他也會跟着改變。而 ImmutableFoo則是在任何情況下均無法修改。

 

Immutable有什麼作用呢?

 

    他們更加容易使用並且安全不易出錯。(更多原因請參看Effective JAVA第二版15條)

 

Immutable vs. unmodifiable

 

    雖然JDK的unmodifiable方法也能保證集合視圖的不變性。但是Immutable能“保證不可改變”,“極易使用”,“更快”,“使用更少的內存(比如ImmutableSet能少2-3X)”。

 

來看例子程序,以前:

Java代碼
  1. public   static   final  Set<Integer> LUCKY_NUMBERS =   
  2.         Collections.unmodifiableSet(new  LinkedHashSet<Integer>(Arrays.asList( 4 8 15 16 23 42 )));  
public static final Set<Integer> LUCKY_NUMBERS = 
        Collections.unmodifiableSet(new LinkedHashSet<Integer>(Arrays.asList(4, 8, 15, 16, 23, 42)));

現在:

Java代碼
  1. public   static   final  ImmutableSet<Integer> LUCKY_NUMBERS =   
  2.         ImmutableSet.of(4 8 15 16 23 42 );  
public static final ImmutableSet<Integer> LUCKY_NUMBERS = 
        ImmutableSet.of(4, 8, 15, 16, 23, 42);

Map 也一樣,以前:

Java代碼
  1. public   static   final  Map<String, Integer> ENGLISH_TO_INT;  
  2.   
  3. static  {  
  4.         Map<String, Integer> map = new  LinkedHashMap<String, Integer>();  
  5.         map.put("four" 4 );  
  6.         map.put("eight" 8 );  
  7.         map.put("fifteen" 15 );  
  8.         map.put("sixteen" 16 );   
  9.         map.put("twenty-three" 23 );  
  10.         map.put("forty-two" 42 );  
  11.         ENGLISH_TO_INT = Collections.unmodifiableMap(map);  
  12. }  
public static final Map<String, Integer> ENGLISH_TO_INT;

static {
        Map<String, Integer> map = new LinkedHashMap<String, Integer>();
        map.put("four", 4);
        map.put("eight", 8);
        map.put("fifteen", 15);
        map.put("sixteen", 16); 
        map.put("twenty-three", 23);
        map.put("forty-two", 42);
        ENGLISH_TO_INT = Collections.unmodifiableMap(map);
}

 現在:

Java代碼
  1. ImmutableMap<String, Integer> map =   
  2.         ImmutableMap.of("four" 4 , "eight" 8 "fifteen" 15 "sixteen" 16 "twenty-three" 23 , "forty-two" 42 );  
ImmutableMap<String, Integer> map = 
        ImmutableMap.of("four", 4,"eight", 8, "fifteen", 15, "sixteen", 16, "twenty-three", 23,"forty-two", 42);

 

在google,In the past, we'd ask, "does this need to be immutable?"

                 Now we ask, "does it need to be mutable?"

 

2,Multisets

 

什麼是Multisets?

 

        當我們有一捆東西的時候我們就會想到用集合,但是我們要用什麼樣的集合呢,在這,我們會考慮以下幾點

        1)他能重複麼,2)他的排序有意義麼,3)他的插入順序

 

        List:有序,可以重複,Set:無序,不可以重複

 

        而MultiSets是無序,可以重複的

 

請看例子,tag,以前:

Java代碼
  1. Map<String, Integer> tags  
  2.         = new  HashMap<String, Integer>();  
  3.   
  4. for  (BlogPost post : getAllBlogPosts()) {  
  5.         for  (String tag : post.getTags()) {  
  6.                 int  value = tags.containsKey(tag) ? tags.get(tag) :  0 ;  
  7.                 tags.put(tag, value + 1 );  
  8.         }  
  9. }  
Map<String, Integer> tags
        = new HashMap<String, Integer>();

for (BlogPost post : getAllBlogPosts()) {
        for (String tag : post.getTags()) {
                int value = tags.containsKey(tag) ? tags.get(tag) : 0;
                tags.put(tag, value + 1);
        }
}

 現在:

Java代碼
  1. Multiset<String> tags = HashMultiset.create();  
  2.         for  (BlogPost post : getAllBlogPosts()) {  
  3.         tags.addAll(post.getTags());  
  4.         System.out.println(tags.toString()); //輸出[sasa, yaomin x 2, jubin x 2, lele]   
  5. }  
Multiset<String> tags = HashMultiset.create();
        for (BlogPost post : getAllBlogPosts()) {
        tags.addAll(post.getTags());
        System.out.println(tags.toString()); //輸出[sasa, yaomin x 2, jubin x 2, lele]
}

 Multiset API

Java代碼
  1. int  count(Object element);  
  2.   
  3. int  add(E element,  int  occurrences); // occurrences是指element出現的次數   
  4.   
  5. boolean  remove(Object element,  int  occurrences);  
  6.   
  7. int  setCount(E element,  int  newCount);  
  8.   
  9. boolean  setCount(E e,  int  oldCount,  int  newCount);  
int count(Object element);

int add(E element, int occurrences);// occurrences是指element出現的次數

boolean remove(Object element, int occurrences);

int setCount(E element, int newCount);

boolean setCount(E e, int oldCount, int newCount);

 Multiset implementations:

        ImmutableMultiset,HashMultiset,LinkedHashMultiset,TreeMultiset,EnumMultiset,ConcurrentMultiset

 

3,Multimaps

 

以前:

Java代碼
  1. Map<Salesperson, List<Sale>> map  
  2.       = new  HashMap<Salesperson, List<Sale>>();  
  3.   
  4. public   void  makeSale(Salesperson salesPerson, Sale sale) {  
  5.       List<Sale> sales = map.get(salesPerson);  
  6.       if  (sales ==  null ) {  
  7.             sales = new  ArrayList<Sale>();  
  8.             map.put(salesPerson, sales);  
  9.       }  
  10.       sales.add(sale);  
  11. }  
Map<Salesperson, List<Sale>> map
      = new HashMap<Salesperson, List<Sale>>();

public void makeSale(Salesperson salesPerson, Sale sale) {
      List<Sale> sales = map.get(salesPerson);
      if (sales == null) {
            sales = new ArrayList<Sale>();
            map.put(salesPerson, sales);
      }
      sales.add(sale);
}

 現在:

Java代碼
  1. Multimap<Salesperson, Sale> multimap  
  2.       = ArrayListMultimap.create();  
  3.   
  4. public   void  makeSale(Salesperson salesPerson, Sale sale) {  
  5.       multimap.put(salesPerson, sale);  
  6. }  
Multimap<Salesperson, Sale> multimap
      = ArrayListMultimap.create();

public void makeSale(Salesperson salesPerson, Sale sale) {
      multimap.put(salesPerson, sale);
}

 什麼是Multimaps?

 

        類似Map的一種以key-value是對的集合,不過他的key不需要唯一。{a=1, a=2, b=3, c=4, c=5, c=6}

 

        multimap.get(key)會返回一個可修改的集合視圖,或者你也可以把它看做Map<K, Collection<V>>

        {a=[1, 2], b=[3], c=[4, 5, 6]}

 

再看一個例子,在上個例子的基礎上找到最大的sale,沒用Multimaps:

Java代碼
  1. public  Sale getBiggestSale() {  
  2.       Sale biggestSale = null ;  
  3.       for  (List<Sale> sales : map.values()) {  
  4.             Sale myBiggestSale = Collections.max(sales,  
  5.                   SALE_CHARGE_COMPARATOR);  
  6.             if  (biggestSale ==  null  ||  
  7.                   myBiggestSale.getCharge() > biggestSale().getCharge()) {  
  8.                   biggestSale = myBiggestSale;  
  9.             }  
  10.       }  
  11.       return  biggestSale;  
  12. }  
public Sale getBiggestSale() {
      Sale biggestSale = null;
      for (List<Sale> sales : map.values()) {
            Sale myBiggestSale = Collections.max(sales,
                  SALE_CHARGE_COMPARATOR);
            if (biggestSale == null ||
                  myBiggestSale.getCharge() > biggestSale().getCharge()) {
                  biggestSale = myBiggestSale;
            }
      }
      return biggestSale;
}

 

用了Multimaps:

Java代碼
  1. public  Sale getBiggestSale() {  
  2.       return  Collections.max(multimap.values(),  
  3.             SALE_CHARGE_COMPARATOR);  
  4. }  
public Sale getBiggestSale() {
      return Collections.max(multimap.values(),
            SALE_CHARGE_COMPARATOR);
}
 

Multimap有6個有用的方法,get(),keys(), keySet(), values(), entries(), asMap()。

 

大多數Map的方法和Multimaps是一樣的,比如說,size(), isEmpty(),containsKey(), containsValue()
put(), putAll(),clear(),values()

 

有些有點區別,比如說,get()返回Collection<V>而不是V,remove(K)變成remove(K,V)和removeAll(K),keySet()變成keys(),entrySet()變成entries()

 

Multimap implementations:ImmutableMultimap,ArrayListMultimap,HashMultimap
      LinkedHashMultimap,TreeMultimap

 

3,BiMap

 

BiMap又名unique-valued map,也就是說,他的key和value都是不能重複的,這就導致了他的key和value能互相轉換,bimap.inverse().inverse() == bimap

 

BiMap implementations:ImmutableBiMap,HashBiMap,EnumBiMap

 

以前:

Java代碼
  1. private   static   final  Map<Integer, String> NUMBER_TO_NAME;  
  2.   private   static   final  Map<String, Integer> NAME_TO_NUMBER;  
  3.     
  4.   static  {  
  5.     NUMBER_TO_NAME = Maps.newHashMap();  
  6.     NUMBER_TO_NAME.put(1 "Hydrogen" );  
  7.     NUMBER_TO_NAME.put(2 "Helium" );  
  8.     NUMBER_TO_NAME.put(3 "Lithium" );  
  9.       
  10.     /* reverse the map programatically so the actual mapping is not repeated */   
  11.     NAME_TO_NUMBER = Maps.newHashMap();  
  12.     for  (Integer number : NUMBER_TO_NAME.keySet()) {  
  13.       NAME_TO_NUMBER.put(NUMBER_TO_NAME.get(number), number);  
  14.     }  
  15.   }  
  16.   
  17.   public   static   int  getElementNumber(String elementName) {  
  18.     return  NUMBER_TO_NAME.get(elementName);  
  19.   }  
  20.   
  21.   public   static  string getElementName( int  elementNumber) {  
  22.     return  NAME_TO_NUMBER.get(elementNumber);  
  23.   }  
private static final Map<Integer, String> NUMBER_TO_NAME;
  private static final Map<String, Integer> NAME_TO_NUMBER;
  
  static {
    NUMBER_TO_NAME = Maps.newHashMap();
    NUMBER_TO_NAME.put(1, "Hydrogen");
    NUMBER_TO_NAME.put(2, "Helium");
    NUMBER_TO_NAME.put(3, "Lithium");
    
    /* reverse the map programatically so the actual mapping is not repeated */
    NAME_TO_NUMBER = Maps.newHashMap();
    for (Integer number : NUMBER_TO_NAME.keySet()) {
      NAME_TO_NUMBER.put(NUMBER_TO_NAME.get(number), number);
    }
  }

  public static int getElementNumber(String elementName) {
    return NUMBER_TO_NAME.get(elementName);
  }

  public static string getElementName(int elementNumber) {
    return NAME_TO_NUMBER.get(elementNumber);
  }

 現在:

Java代碼
  1. private   static   final  BiMap<Integer,String> NUMBER_TO_NAME_BIMAP;  
  2.     
  3.   static  {  
  4.     NUMBER_TO_NAME_BIMAP = Maps.newHashBiMap();  
  5.     NUMBER_TO_NAME_BIMAP.put(1 "Hydrogen" );  
  6.     NUMBER_TO_NAME_BIMAP.put(2 "Helium" );  
  7.     NUMBER_TO_NAME_BIMAP.put(3 "Lithium" );  
  8.   }  
  9.   
  10.   public   static   int  getElementNumber(String elementName) {  
  11.     return  NUMBER_TO_NAME_BIMAP.inverse().get(elementName);  
  12.   }  
  13.   
  14.   public   static  string getElementName( int  elementNumber) {  
  15.     return  NUMBER_TO_NAME_BIMAP.get(elementNumber);  
  16.   }  
private static final BiMap<Integer,String> NUMBER_TO_NAME_BIMAP;
  
  static {
    NUMBER_TO_NAME_BIMAP = Maps.newHashBiMap();
    NUMBER_TO_NAME_BIMAP.put(1, "Hydrogen");
    NUMBER_TO_NAME_BIMAP.put(2, "Helium");
    NUMBER_TO_NAME_BIMAP.put(3, "Lithium");
  }

  public static int getElementNumber(String elementName) {
    return NUMBER_TO_NAME_BIMAP.inverse().get(elementName);
  }

  public static string getElementName(int elementNumber) {
    return NUMBER_TO_NAME_BIMAP.get(elementNumber);
  }

 更好的:

Java代碼
  1. private   static   final  BiMap<Integer,String> NUMBER_TO_NAME_BIMAP  
  2.     = new  ImmutableBiMapBuilder<Integer,String>()  
  3.         .put(1 "Hydrogen" )  
  4.         .put(2 "Helium" )  
  5.         .put(3 "Lithium" )  
  6.         .getBiMap(); 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章