带你领略 Google Collections - 无刃之锋的小坑 - JavaEye技术网站

来源:百度文库 编辑:神马文学网 时间:2024/04/28 08:32:11

带你领略 Google Collections

关键字: 工具类

    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 LUCKY_NUMBERS =   
  2.         Collections.unmodifiableSet(new LinkedHashSet(Arrays.asList(4, 8, 15, 16, 23, 42)));  

现在:

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

Map也一样,以前:

Java代码
  1. public static final Map ENGLISH_TO_INT;  
  2.   
  3. static {  
  4.         Map map = new LinkedHashMap();  
  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. }  

 现在:

Java代码
  1. ImmutableMap map =   
  2.         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 tags  
  2.         = new HashMap();  
  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. }  

 现在:

Java代码
  1. Multiset 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 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);  

 Multiset implementations:

        ImmutableMultiset,HashMultiset,LinkedHashMultiset,TreeMultiset,EnumMultiset,ConcurrentMultiset

 

3,Multimaps

 

以前:

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

 现在:

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

 什么是Multimaps?

 

        类似Map的一种以key-value是对的集合,不过他的key不需要唯一。{a=1, a=2, b=3, c=4, c=5, c=6}

 

        multimap.get(key)会返回一个可修改的集合视图,或者你也可以把它看做Map>

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

 

再看一个例子,在上个例子的基础上找到最大的sale,没用Multimaps:

Java代码
  1. public Sale getBiggestSale() {  
  2.       Sale biggestSale = null;  
  3.       for (List 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. }  

 

用了Multimaps:

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

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

 

大多数Map的方法和Multimaps是一样的,比如说,size(), isEmpty(),containsKey(), containsValue()
put(), putAll(),clear(),values()

 

有些有点区别,比如说,get()返回Collection而不是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 NUMBER_TO_NAME;  
  2.   private static final Map 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.   }  

 现在:

Java代码
  1. private static final BiMap 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.   }  

 更好的:

Java代码
  1. private static final BiMap NUMBER_TO_NAME_BIMAP  
  2.     = new ImmutableBiMapBuilder()  
  3.         .put(1, "Hydrogen")  
  4.         .put(2, "Helium")  
  5.         .put(3, "Lithium")  
  6.         .getBiMap();