带你领略 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(); 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章