linkin大话数据结构--Google commons工具类

package tz.web.dao.bean;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.primitives.Ints;

public class Linkin {
    public static void main(String[] args) {

        //去除空值的字符串连接
        Joiner joiner = Joiner.on("; ").skipNulls();
        String str = joiner.join("Harry", null, "Ron", "Hermione");
        System.out.println(str);
        //数组连接成字符串
        String retn = Joiner.on(",").join(Arrays.asList(1, 5, 7));
        System.out.println(retn);
        //字符串的拆分
        Iterable<String> it = Splitter.on(',').split("a,b,c");
        for (String str1 : it) 
        {
            System.out.println(str1);
        }
        //字符串的拆分 去除空字符串和空格
        Iterable<String> it1 = Splitter.on(',').trimResults().omitEmptyStrings().split("foo,bar,,   qux");
        for (String str2 : it1) 
        {
            System.out.println(str2);
        }

        //直接省去泛型来初始化list
        List<String> list = Lists.newArrayList();
        System.out.println(list);
        //连里面的对象也直接初始化进去
        List<String> list1 = Lists.newArrayList("1","2","3");
        System.out.println(list1);
        //数组转换成list集合
        List<Integer> ints = Ints.asList(1, 2, 3);
        System.out.println(ints);
        //list元素的反转
        List<Integer> ints1 = Lists.reverse(ints);
        System.out.println(ints1);
        //构造一个不可变的List
        ImmutableList<String> list2 = ImmutableList.of("1", "2", "3");
        System.out.println(list2);
        //将map丢在一个set里面,这样子这个map里面的东西就可以放在set里了
        Map<String, Integer> map = ImmutableMap.of("a", 1, "b", 2, "c", 3);
        Set<Entry<String, Integer>> set = map.entrySet();
        for (Entry<String, Integer> entry : set) {
            System.out.println(entry.getKey() + " : " + entry.getValue());
        }
        //一键多值Map
        Multimap<String, String> multimap = ArrayListMultimap.create();
        multimap.put("a", "1");
        multimap.put("a", "2");
        multimap.put("b", "3");
        multimap.put("b", "4");
        Collection<String> strs = multimap.get("a");
        System.out.println(strs);//这里返回的key的多个value
        //双向Map
        HashBiMap<String, String> bm = HashBiMap.create();
        bm.put("a", "1");
        bm.put("b", "2");
        bm.put("c", "3");
        System.out.println(bm.get("a"));
        System.out.println(bm.inverse().get("2"));

    }

}

  • Google Guava Collections 使用介绍
Google Guava Collections(以下都简称为 Guava Collections)是 Java Collections Framework 的增强和扩展。每个 Java 开发者都会在工作中使用各种数据结构,很多情况下 Java Collections Framework 可以帮助你完成这类工作。但是在有些场合你使用了 Java Collections Framework 的 API,但还是需要写很多代码来实现一些复杂逻辑,这个时候就可以尝试使用 Guava Collections 来帮助你完成这些工作。这些高质量的 API 使你的代码更短,更易于阅读和修改,工作更加轻松。


对于理解 Java 开源工具来说,本文读者至少应具备基础的 Java 知识,特别是 JDK5 的特性。因为 Guava Collections 充分使用了范型,循环增强这样的特性。作为 Java Collections Framework 的增强,读者必须对 Java Collections Framework 有清晰的理解,包括主要的接口约定和常用的实现类。并且 Guava Collections 很大程度上是帮助开发者完成比较复杂的数据结构的操作,因此基础的数据结构和算法的知识也是清晰理解 Guava Collections 的必要条件。


Guava Collections 是 Google 的工程师 Kevin Bourrillion 和 Jared Levy 在著名"20%"时间写的代码。当然作为开源项目还有其他的开发者贡献了代码。在编写的过程中,Java Collections Framework 的作者 Joshua Bloch 也参与了代码审核和提出建议。目前它已经移到另外一个叫 guava-libraries 的开源项目下面来维护。
因为功能相似而且又同是开源项目,人们很很自然会把它和 Apache Commons Collections 来做比较。其区别归结起来有以下几点:

Guava Collections 充分利用了 JDK5 的范型和枚举这样的特性,而 Apache Commons Collections 则是基于 JDK1.2。其次 Guava Collections 更加严格遵守 Java Collections Framework 定义的接口契约,而在 Apache Commons Collections 你会发现不少违反这些 JDK 接口契约的地方。这些不遵守标准的地方就是出 bug 的风险很高。最后 Guava Collections 处于积极的维护状态,本文介绍的特性都基于目前最新 2011 年 4 月的 Guava r09 版本,而 Apache Commons Collections 最新一次发布也已经是 2008 年了。


  • 功能列举:
可以说 Java Collections Framework 满足了我们大多数情况下使用集合的要求,但是当遇到一些特殊的情况我们的代码会比较冗长,比较容易出错。Guava Collections 可以帮助你的代码更简短精炼,更重要是它增强了代码的可读性。看看 Guava Collections 为我们做了哪些很酷的事情。
Immutable Collections: 还在使用 Collections.unmodifiableXXX() ? Immutable Collections 这才是真正的不可修改的集合
Multiset: 看看如何把重复的元素放入一个集合
Multimaps: 需要在一个 key 对应多个 value 的时候 , 自己写一个实现比较繁琐 - 让 Multimaps 来帮忙
BiMap: java.util.Map 只能保证 key 的不重复,BiMap 保证 value 也不重复
MapMaker: 超级强大的 Map 构造类
Ordering class: 大家知道用 Comparator 作为比较器来对集合排序,但是对于多关键字排序 Ordering class 可以简化很多的代码
  • 其他特性:
当然,如果没有 Guava Collections 你也可以用 Java Collections Framework 完成上面的功能。但是 Guava Collections 提供的这些 API 经过精心设计,而且还有 25000 个单元测试来保障它的质量。所以我们没必要重新发明轮子。接下来我们来详细看看 Guava Collections 的一些具体功能。


  • Immutable Collections: 真正的不可修改的集合
大家都用过 Collections.unmodifiableXXX() 来做一个不可修改的集合。例如你要构造存储常量的 Set,你可以这样来做 :
 Set<String> set = new HashSet<String>(Arrays.asList(new String[]{"RED", "GREEN"})); 
 Set<String> unmodifiableSet = Collections.unmodifiableSet(set);
这看上去似乎不错,因为每次调 unmodifiableSet.add() 都会抛出一个 UnsupportedOperationException。感觉安全了?慢!如果有人在原来的 set 上 add 或者 remove 元素会怎么样?结果 unmodifiableSet 也是被 add 或者 remove 元素了。而且构造这样一个简单的 set 写了两句长的代码。下面看看 ImmutableSet 是怎么来做地更安全和简洁 :
 ImmutableSet<String> immutableSet = ImmutableSet.of("RED", "GREEN");
就这样一句就够了,而且试图调 add 方法的时候,它一样会抛出 UnsupportedOperationException。重要的是代码的可读性增强了不少,非常直观地展现了代码的用意。如果像之前这个代码保护一个 set 怎么做呢?你可以 :
 ImmutableSet<String> immutableSet = ImmutableSet.copyOf(set);
从构造的方式来说,ImmutableSet 集合还提供了 Builder 模式来构造一个集合 :
 Builder<String>  builder = ImmutableSet.builder(); 
 ImmutableSet<String> immutableSet = builder.add("RED").addAll(set).build();
在这个例子里面 Builder 不但能加入单个元素还能加入既有的集合。
除此之外,Guava Collections 还提供了各种 Immutable 集合的实现:ImmutableList,ImmutableMap,ImmutableSortedSet,ImmutableSortedMap。


  • Multiset: 把重复的元素放入集合
你可能会说这和 Set 接口的契约冲突,因为 Set 接口的 JavaDoc 里面规定不能放入重复元素。事实上,Multiset 并没有实现 java.util.Set 接口,它更像是一个 Bag。普通的 Set 就像这样 :[car, ship, bike],而 Multiset 会是这样 : [car x 2, ship x 6, bike x 3]。
譬如一个 List 里面有各种字符串,然后你要统计每个字符串在 List 里面出现的次数 :
 Map<String, Integer> map = new HashMap<String, Integer>(); 
 for(String word : wordList){ 
    Integer count = map.get(word); 
    map.put(word, (count == null) ? 1 : count + 1); 
 } 
 //count word “the”
 Integer count = map.get(“the”);
如果用 Multiset 就可以这样 :
 HashMultiset<String> multiSet = HashMultiset.create(); 
 multiSet.addAll(wordList); 
 //count word “the”
 Integer count = multiSet.count(“the”);
这样连循环都不用了,而且 Multiset 用的方法叫 count,显然比在 Map 里面调 get 有更好的可读性。Multiset 还提供了 setCount 这样设定元素重复次数的方法,虽然你可以通过使用 Map 来实现类似的功能,但是程序的可读性比 Multiset 差了很多。
常用实现 Multiset 接口的类有:
HashMultiset: 元素存放于 HashMap
LinkedHashMultiset: 元素存放于 LinkedHashMap,即元素的排列顺序由第一次放入的顺序决定
TreeMultiset:元素被排序存放于TreeMap
EnumMultiset: 元素必须是 enum 类型
ImmutableMultiset: 不可修改的 Mutiset
看到这里你可能已经发现 Guava Collections 都是以 create 或是 of 这样的静态方法来构造对象。这是因为这些集合类大多有多个参数的私有构造方法,由于参数数目很多,客户代码程序员使用起来就很不方便。而且以这种方式可以返回原类型的子类型对象。另外,对于创建范型对象来讲,这种方式更加简洁。


  • Multimap: 在 Map 的 value 里面放多个元素
Muitimap 就是一个 key 对应多个 value 的数据结构。看上去它很像 java.util.Map 的结构,但是 Muitimap 不是 Map,没有实现 Map 的接口。设想你对 Map 调了 2 次参数 key 一样的 put 方法,结果就是第 2 次的 value 覆盖了第 1 次的 value。但是对 Muitimap 来说这个 key 同时对应了 2 个 value。所以 Map 看上去是 : {k1=v1, k2=v2,...},而 Muitimap 是 :{k1=[v1, v2, v3], k2=[v7, v8],....}。
举个记名投票的例子。所有选票都放在一个 List<Ticket> 里面,List 的每个元素包括投票人和选举人的名字。我们可以这样写 :
 //Key is candidate name, its value is his voters 
 HashMap<String, HashSet<String>> hMap = new HashMap<String, HashSet<String>>(); 
 for(Ticket ticket: tickets){ 
    HashSet<String> set = hMap.get(ticket.getCandidate()); 
    if(set == null){ 
        set = new HashSet<String>(); 
        hMap.put(ticket.getCandidate(), set); 
    } 
    set.add(ticket.getVoter()); 
 }
我们再来看看 Muitimap 能做些什么 :
 HashMultimap<String, String> map = HashMultimap.create(); 
 for(Ticket ticket: tickets){ 
    map.put(ticket.getCandidate(), ticket.getVoter()); 
 }
就这么简单!
Muitimap 接口的主要实现类有:
HashMultimap: key 放在 HashMap,而 value 放在 HashSet,即一个 key 对应的 value 不可重复
ArrayListMultimap: key 放在 HashMap,而 value 放在 ArrayList,即一个 key 对应的 value 有顺序可重复
LinkedHashMultimap: key 放在 LinkedHashMap,而 value 放在 LinkedHashSet,即一个 key 对应的 value 有顺序不可重复
TreeMultimap: key 放在 TreeMap,而 value 放在 TreeSet,即一个 key 对应的 value 有排列顺序
ImmutableMultimap: 不可修改的 Multimap


  • BiMap: 双向 Map
BiMap 实现了 java.util.Map 接口。它的特点是它的 value 和它 key 一样也是不可重复的,换句话说它的 key 和 value 是等价的。如果你往 BiMap 的 value 里面放了重复的元素,就会得到 IllegalArgumentException。
举个例子,你可能经常会碰到在 Map 里面根据 value 值来反推它的 key 值的逻辑:
 for(Map.Entry<User, Address> entry : map.entreSet()){ 
    if(entry.getValue().equals(anAddess)){ 
        return entry.getKey(); 
    } 
 } 
 return null;
如果把 User 和 Address 都放在 BiMap,那么一句代码就得到结果了:
 return biMap.inverse().get(anAddess);
这里的 inverse 方法就是把 BiMap 的 key 集合 value 集合对调,因此 biMap == biMap.inverse().inverse()。
BiMap的常用实现有:
HashBiMap: key 集合与 value 集合都有 HashMap 实现
EnumBiMap: key 与 value 都必须是 enum 类型
ImmutableBiMap: 不可修改的 BiMap


  • MapMaker: 超级强大的 Map 构造工具
MapMaker 是用来构造 ConcurrentMap 的工具类。为什么可以把 MapMaker 叫做超级强大?看了下面的例子你就知道了。首先,它可以用来构造 ConcurrentHashMap:
 //ConcurrentHashMap with concurrency level 8 
 ConcurrentMap<String, Object> map1 = new MapMaker() 
    .concurrencyLevel(8) 
     .makeMap();
或者构造用各种不同 reference 作为 key 和 value 的 Map:
 //ConcurrentMap with soft reference key and weak reference value 
 ConcurrentMap<String, Object> map2 = new MapMaker() 
    .softKeys() 
    .weakValues() 
    .makeMap();
或者构造有自动移除时间过期项的 Map:
 //Automatically removed entries from map after 30 seconds since they are created 
 ConcurrentMap<String, Object> map3 = new MapMaker() 
    .expireAfterWrite(30, TimeUnit.SECONDS) 
    .makeMap();
或者构造有最大限制数目的 Map:
 //Map size grows close to the 100, the map will evict 
 //entries that are less likely to be used again 
 ConcurrentMap<String, Object> map4 = new MapMaker() 
    .maximumSize(100) 
    .makeMap();
或者提供当 Map 里面不包含所 get 的项,而需要自动加入到 Map 的功能。这个功能当 Map 作为缓存的时候很有用 :
 //Create an Object to the map, when get() is missing in map 
 ConcurrentMap<String, Object> map5 = new MapMaker() 
    .makeComputingMap( 
      new Function<String, Object>() { 
        public Object apply(String key) { 
          return createObject(key); 
    }});
这些还不是最强大的特性,最厉害的是 MapMaker 可以提供拥有以上所有特性的 Map:
 //Put all features together! 
 ConcurrentMap<String, Object> mapAll = new MapMaker() 
    .concurrencyLevel(8) 
    .softKeys() 
    .weakValues() 
    .expireAfterWrite(30, TimeUnit.SECONDS) 
    .maximumSize(100) 
    .makeComputingMap( 
      new Function<String, Object>() { 
        public Object apply(String key) { 
          return createObject(key); 
     }});


Ordering class: 灵活的多字段排序比较器
要对集合排序或者求最大值最小值,首推 java.util.Collections 类,但关键是要提供 Comparator 接口的实现。假设有个待排序的 List<Foo>,而 Foo 里面有两个排序关键字 int a, int b 和 int c:
 Collections.sort(list, new Comparator<Foo>(){    
    @Override    
    public int compare(Foo f1, Foo f2) {    
        int resultA = f1.a – f2.a; 
        int resultB = f1.b – f2.b; 
        return  resultA == 0 ? (resultB == 0 ? f1.c – f2.c : resultB) : resultA;
}});
这看上去有点眼晕,如果用一串 if-else 也好不到哪里去。看看 ComparisonChain 能做到什么 :
 Collections.sort(list, new Comparator<Foo>(){    
    @Override 
    return ComparisonChain.start()  
         .compare(f1.a, f2.a)  
         .compare(f1.b, f2.b) 
         .compare(f1.c, f2.c).result(); 
         }});
如果排序关键字要用自定义比较器,compare 方法也有接受 Comparator 的重载版本。譬如 Foo 里面每个排序关键字都已经有了各自的 Comparator,那么利用 ComparisonChain 可以 :
 Collections.sort(list, new Comparator<Foo>(){    
    @Override 
    return ComparisonChain.start()  
         .compare(f1.a, f2.a, comparatorA)  
         .compare(f1.b, f2.b, comparatorB) 
         .compare(f1.c, f2.c, comparatorC).result(); 
         }});
Ordring 类还提供了一个组合 Comparator 对象的方法。而且 Ordring 本身实现了 Comparator 接口所以它能直接作为 Comparator 使用:
 Ordering<Foo> ordering = Ordering.compound(
     Arrays.asList(comparatorA, comparatorB, comparatorc)); 
 Collections.sort(list, ordering);


其他特性 :
过滤器:利用 Collections2.filter() 方法过滤集合中不符合条件的元素。譬如过滤一个 List<Integer> 里面小于 10 的元素 :
 Collection<Integer>  filterCollection = 
        Collections2.filter(list, new Predicate<Integer>(){ 
    @Override 
    public boolean apply(Integer input) { 
        return input >= 10; 
 }});
当然,你可以自己写一个循环来实现这个功能,但是这样不能保证之后小于 10 的元素不被放入集合。filter 的强大之处在于返回的 filterCollection 仍然有排斥小于 10 的元素的特性,如果调 filterCollection.add(9) 就会得到一个 IllegalArgumentException。
转换器:利用 Collections2.transform() 方法来转换集合中的元素。譬如把一个 Set<Integer> 里面所有元素都转换成带格式的 String 来产生新的 Collection<String>:
 Collection<String>  formatCollection = 
      Collections2.transform(set, new Function<Integer, String>(){ 
    @Override 
    public String apply(Integer input) { 
        return new DecimalFormat("#,###").format(input); 
 }} );


  • 下载与使用
这个开源项目发布的 jar 包可以在它的官方网站内(http://code.google.com/p/guava-libraries/downloads/list)找到。其下载的 zip 包中含有 Guava Collections 的 jar 包 guava-r09.jar 及其依赖包 guava-r09-gwt.jar,javadoc,源代码,readme 等文件。使用时只需将 guava-r09.jar 和依赖包 guava-r09-gwt.jar 放入 CLASSPATH 中即可。
如果您使用 Maven 作为构建工具的话可以在 pom.xml 内加入:
 <dependency> 
    <groupId>com.google.guava</groupId> 
    <artifactId>guava</artifactId> 
    <version>r09</version> 
 </dependency>
需要注意的是本文介绍的 Guava r09 需要 1.5 或者更高版本的 JDK。


以上介绍了 Guava Collections 的一些基本的功能特性。你可以从 guava-libraries 的官方网站下载它的 jar 包和它其他的相关文档。如果你使用 Maven 来管理你的项目依赖包,Maven 中央库也提供了它版本的依赖。最后希望 Guava Collections 使你的编程工作更轻松,更有乐趣。


任何对JDK集合框架有经验的程序员都熟悉和喜欢java.util.Collections包含的工具方法。Guava沿着这些路线提供了更多的工具方法:适用于所有集合的静态方法。这是Guava最流行和成熟的部分之一。


我们用相对直观的方式把工具类与特定集合接口的对应关系归纳如下:


集合接口 属于JDK还是Guava 对应的Guava工具类
Collection JDK Collections2:不要和java.util.Collections混淆
List JDK Lists
Set JDK Sets
SortedSet JDK Sets
Map JDK Maps
SortedMap JDK Maps
Queue JDK Queues
Multiset Guava Multisets
Multimap Guava Multimaps
BiMap Guava Maps
Table Guava Tables



静态工厂方法
在JDK 7之前,构造新的范型集合时要讨厌地重复声明范型:

List<TypeThatsTooLongForItsOwnGood> list = new ArrayList<TypeThatsTooLongForItsOwnGood>();
我想我们都认为这很讨厌。因此Guava提供了能够推断范型的静态工厂方法:


List<TypeThatsTooLongForItsOwnGood> list = Lists.newArrayList();

Map<KeyType, LongishValueType> map = Maps.newLinkedHashMap();
可以肯定的是,JDK7版本的钻石操作符(<>)没有这样的麻烦:


List<TypeThatsTooLongForItsOwnGood> list = new ArrayList<>();
但Guava的静态工厂方法远不止这么简单。用工厂方法模式,我们可以方便地在初始化时就指定起始元素。

Set<Type> copySet = Sets.newHashSet(elements);
List<String> theseElements = Lists.newArrayList("alpha", "beta", "gamma");
此外,通过为工厂方法命名(Effective Java第一条),我们可以提高集合初始化大小的可读性:

List<Type> exactly100 = Lists.newArrayListWithCapacity(100);
List<Type> approx100 = Lists.newArrayListWithExpectedSize(100);
Set<Type> approx100Set = Sets.newHashSetWithExpectedSize(100);
确切的静态工厂方法和相应的工具类一起罗列在下面的章节。


注意:Guava引入的新集合类型没有暴露原始构造器,也没有在工具类中提供初始化方法。而是直接在集合类中提供了静态工厂方法,例如:


Multiset<String> multiset = HashMultiset.create();
Iterables
在可能的情况下,Guava提供的工具方法更偏向于接受Iterable而不是Collection类型。在Google,对于不存放在主存的集合——比如从数据库或其他数据中心收集的结果集,因为实际上还没有攫取全部数据,这类结果集都不能支持类似size()的操作 ——通常都不会用Collection类型来表示
因此,很多你期望的支持所有集合的操作都在Iterables类中。大多数Iterables方法有一个在Iterators类中的对应版本,用来处理Iterator。

截至Guava 1.2版本,Iterables使用FluentIterable类进行了补充,它包装了一个Iterable实例,并对许多操作提供了”fluent”(链式调用)语法。


下面列出了一些最常用的工具方法,但更多Iterables的函数式方法将在第四章讨论。


  • 常规方法


concat(Iterable<Iterable>) 串联多个iterables的懒视图* concat(Iterable...)
frequency(Iterable, Object) 返回对象在iterable中出现的次数 与Collections.frequency (Collection,   Object)比较;Multiset
partition(Iterable, int) 把iterable按指定大小分割,得到的子集都不能进行修改操作 Lists.partition(List, int);paddedPartition(Iterable, int)
getFirst(Iterable, T default) 返回iterable的第一个元素,若iterable为空则返回默认值 与Iterable.iterator(). next()比较;FluentIterable.first()
getLast(Iterable) 返回iterable的最后一个元素,若iterable为空则抛出NoSuchElementException getLast(Iterable, T default);
FluentIterable.last()
elementsEqual(Iterable, Iterable) 如果两个iterable中的所有元素相等且顺序一致,返回true 与List.equals(Object)比较
unmodifiableIterable(Iterable) 返回iterable的不可变视图 与Collections. unmodifiableCollection(Collection)比较
limit(Iterable, int) 限制iterable的元素个数限制给定值 FluentIterable.limit(int)
getOnlyElement(Iterable) 获取iterable中唯一的元素,如果iterable为空或有多个元素,则快速失败 getOnlyElement(Iterable, T default)
*译者注:懒视图意味着如果还没访问到某个iterable中的元素,则不会对它进行串联操作。



Iterable<Integer> concatenated = Iterables.concat(
        Ints.asList(1, 2, 3),
        Ints.asList(4, 5, 6)); // concatenated包括元素 1, 2, 3, 4, 5, 6
String lastAdded = Iterables.getLast(myLinkedHashSet);
String theElement = Iterables.getOnlyElement(thisSetIsDefinitelyASingleton);
//如果set不是单元素集,就会出错了!
与Collection方法相似的工具方法


通常来说,Collection的实现天然支持操作其他Collection,但却不能操作Iterable。


下面的方法中,如果传入的Iterable是一个Collection实例,则实际操作将会委托给相应的Collection接口方法。例如,往Iterables.size方法传入是一个Collection实例,它不会真的遍历iterator获取大小,而是直接调用Collection.size。


方法 类似的Collection方法 等价的FluentIterable方法
addAll(Collection addTo,   Iterable toAdd) Collection.addAll(Collection)
contains(Iterable, Object) Collection.contains(Object) FluentIterable.contains(Object)
removeAll(Iterable   removeFrom, Collection toRemove) Collection.removeAll(Collection)
retainAll(Iterable   removeFrom, Collection toRetain) Collection.retainAll(Collection)
size(Iterable) Collection.size() FluentIterable.size()
toArray(Iterable, Class) Collection.toArray(T[]) FluentIterable.toArray(Class)
isEmpty(Iterable) Collection.isEmpty() FluentIterable.isEmpty()
get(Iterable, int) List.get(int) FluentIterable.get(int)
toString(Iterable) Collection.toString() FluentIterable.toString()
FluentIterable


FluentIterable还有一些便利方法用来把自己拷贝到不可变集合


ImmutableList
ImmutableSet toImmutableSet()
ImmutableSortedSet toImmutableSortedSet(Comparator)
Lists
除了静态工厂方法和函数式编程方法,Lists为List类型的对象提供了若干工具方法。


方法 描述
partition(List, int) 把List按指定大小分割
reverse(List) 返回给定List的反转视图。注: 如果List是不可变的,考虑改用ImmutableList.reverse()。
List countUp = Ints.asList(1, 2, 3, 4, 5);
List countDown = Lists.reverse(theList); // {5, 4, 3, 2, 1}
List<List> parts = Lists.partition(countUp, 2);//{{1,2}, {3,4}, {5}}
静态工厂方法


Lists提供如下静态工厂方法:


具体实现类型 工厂方法
ArrayList basic, with elements, from Iterable, with exact capacity, with expected size, from Iterator
LinkedList basic, from Iterable
Sets
Sets工具类包含了若干好用的方法。


  • 集合理论方法


我们提供了很多标准的集合运算(Set-Theoretic)方法,这些方法接受Set参数并返回SetView,可用于:


直接当作Set使用,因为SetView也实现了Set接口;
用copyInto(Set)拷贝进另一个可变集合;
用immutableCopy()对自己做不可变拷贝。
方法
union(Set, Set)
intersection(Set, Set)
difference(Set, Set)
symmetricDifference(Set,   Set)
使用范例:


Set<String> wordsWithPrimeLength = ImmutableSet.of("one", "two", "three", "six", "seven", "eight");
Set<String> primes = ImmutableSet.of("two", "three", "five", "seven");
SetView<String> intersection = Sets.intersection(primes,wordsWithPrimeLength);
// intersection包含"two", "three", "seven"
return intersection.immutableCopy();//可以使用交集,但不可变拷贝的读取效率更高
  • 其他Set工具方法


方法 描述 另请参见
cartesianProduct(List<Set>) 返回所有集合的笛卡儿积 cartesianProduct(Set...)
powerSet(Set) 返回给定集合的所有子集

Set<String> animals = ImmutableSet.of("gerbil", "hamster");
Set<String> fruits = ImmutableSet.of("apple", "orange", "banana");
Set<List<String>> product = Sets.cartesianProduct(animals, fruits);
// {{"gerbil", "apple"}, {"gerbil", "orange"}, {"gerbil", "banana"},
//  {"hamster", "apple"}, {"hamster", "orange"}, {"hamster", "banana"}
Set<Set<String>> animalSets = Sets.powerSet(animals);
// {{}, {"gerbil"}, {"hamster"}, {"gerbil", "hamster"}}
静态工厂方法


  • Sets提供如下静态工厂方法:


具体实现类型 工厂方法
HashSet basic, with elements, from Iterable, with expected size, from Iterator
LinkedHashSet basic, from Iterable, with expected size
TreeSet basic, with Comparator, from Iterable
Maps
Maps类有若干值得单独说明的、很酷的方法。


uniqueIndex


Maps.uniqueIndex(Iterable,Function)通常针对的场景是:有一组对象,它们在某个属性上分别有独一无二的值,而我们希望能够按照这个属性值查找对象——译者注:这个方法返回一个Map,键为Function返回的属性值,值为Iterable中相应的元素,因此我们可以反复用这个Map进行查找操作。


比方说,我们有一堆字符串,这些字符串的长度都是独一无二的,而我们希望能够按照特定长度查找字符串:


ImmutableMap<Integer, String> stringsByIndex = Maps.uniqueIndex(strings,
    new Function<String, Integer> () {
        public Integer apply(String string) {
            return string.length();
        }
    });
如果索引值不是独一无二的,请参见下面的Multimaps.index方法。


difference


Maps.difference(Map, Map)用来比较两个Map以获取所有不同点。该方法返回MapDifference对象,把不同点的维恩图分解为:


entriesInCommon() 两个Map中都有的映射项,包括匹配的键与值
entriesDiffering() 键相同但是值不同值映射项。返回的Map的值类型为MapDifference.ValueDifference,以表示左右两个不同的值
entriesOnlyOnLeft() 键只存在于左边Map的映射项
entriesOnlyOnRight() 键只存在于右边Map的映射项
Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3);
Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3);
MapDifference<String, Integer> diff = Maps.difference(left, right);
diff.entriesInCommon(); // {"b" => 2}
diff.entriesInCommon(); // {"b" => 2}
diff.entriesOnlyOnLeft(); // {"a" => 1}
diff.entriesOnlyOnRight(); // {"d" => 5}
处理BiMap的工具方法


Guava中处理BiMap的工具方法在Maps类中,因为BiMap也是一种Map实现。


  • BiMap工具方法 相应的Map工具方法
synchronizedBiMap(BiMap) Collections.synchronizedMap(Map)
unmodifiableBiMap(BiMap) Collections.unmodifiableMap(Map)
静态工厂方法


Maps提供如下静态工厂方法:


具体实现类型 工厂方法
HashMap basic, from Map, with expected size
LinkedHashMap basic, from Map
TreeMap basic, from Comparator, from SortedMap
EnumMap from Class, from Map
ConcurrentMap:支持所有操作 basic
IdentityHashMap basic
Multisets
标准的Collection操作会忽略Multiset重复元素的个数,而只关心元素是否存在于Multiset中,如containsAll方法。为此,Multisets提供了若干方法,以顾及Multiset元素的重复性:


方法 说明 和Collection方法的区别
containsOccurrences(Multiset   sup, Multiset sub) 对任意o,如果sub.count(o)<=super.count(o),返回true Collection.containsAll忽略个数,而只关心sub的元素是否都在super中
removeOccurrences(Multiset   removeFrom, Multiset toRemove) 对toRemove中的重复元素,仅在removeFrom中删除相同个数。 Collection.removeAll移除所有出现在toRemove的元素
retainOccurrences(Multiset   removeFrom, Multiset toRetain) 修改removeFrom,以保证任意o都符合removeFrom.count(o)<=toRetain.count(o) Collection.retainAll保留所有出现在toRetain的元素
intersection(Multiset,   Multiset) 返回两个multiset的交集; 没有类似方法
Multiset<String> multiset1 = HashMultiset.create();
multiset1.add("a", 2);
Multiset<String> multiset2 = HashMultiset.create();
multiset2.add("a", 5);
multiset1.containsAll(multiset2); //返回true;因为包含了所有不重复元素,
//虽然multiset1实际上包含2个"a",而multiset2包含5个"a"
Multisets.containsOccurrences(multiset1, multiset2); // returns false
multiset2.removeOccurrences(multiset1); // multiset2 现在包含3个"a"
multiset2.removeAll(multiset1);//multiset2移除所有"a",虽然multiset1只有2个"a"
multiset2.isEmpty(); // returns true
Multisets中的其他工具方法还包括:


copyHighestCountFirst(Multiset) 返回Multiset的不可变拷贝,并将元素按重复出现的次数做降序排列
unmodifiableMultiset(Multiset) 返回Multiset的只读视图
unmodifiableSortedMultiset(SortedMultiset) 返回SortedMultiset的只读视图
Multiset<String> multiset = HashMultiset.create();
multiset.add("a", 3);
multiset.add("b", 5);
multiset.add("c", 1);
ImmutableMultiset highestCountFirst = Multisets.copyHighestCountFirst(multiset);
//highestCountFirst,包括它的entrySet和elementSet,按{"b", "a", "c"}排列元素
Multimaps
Multimaps提供了若干值得单独说明的通用工具方法


  • index


作为Maps.uniqueIndex的兄弟方法,Multimaps.index(Iterable, Function)通常针对的场景是:有一组对象,它们有共同的特定属性,我们希望按照这个属性的值查询对象,但属性值不一定是独一无二的。


比方说,我们想把字符串按长度分组。


ImmutableSet digits = ImmutableSet.of("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine");
Function<String, Integer> lengthFunction = new Function<String, Integer>() {
    public Integer apply(String string) {
        return string.length();
    }
};
ImmutableListMultimap<Integer, String> digitsByLength= Multimaps.index(digits, lengthFunction);
/*
*  digitsByLength maps:
*  3 => {"one", "two", "six"}
*  4 => {"zero", "four", "five", "nine"}
*  5 => {"three", "seven", "eight"}
*/
invertFrom


鉴于Multimap可以把多个键映射到同一个值(译者注:实际上这是任何map都有的特性),也可以把一个键映射到多个值,反转Multimap也会很有用。Guava 提供了invertFrom(Multimap toInvert,
Multimap dest)做这个操作,并且你可以自由选择反转后的Multimap实现。


注:如果你使用的是ImmutableMultimap,考虑改用ImmutableMultimap.inverse()做反转。


ArrayListMultimap<String, Integer> multimap = ArrayListMultimap.create();
multimap.putAll("b", Ints.asList(2, 4, 6));
multimap.putAll("a", Ints.asList(4, 2, 1));
multimap.putAll("c", Ints.asList(2, 5, 3));
TreeMultimap<Integer, String> inverse = Multimaps.invertFrom(multimap, TreeMultimap<String, Integer>.create());
//注意我们选择的实现,因为选了TreeMultimap,得到的反转结果是有序的
/*
* inverse maps:
*  1 => {"a"}
*  2 => {"a", "b", "c"}
*  3 => {"c"}
*  4 => {"a", "b"}
*  5 => {"c"}
*  6 => {"b"}
*/
forMap


想在Map对象上使用Multimap的方法吗?forMap(Map)把Map包装成SetMultimap。这个方法特别有用,例如,与Multimaps.invertFrom结合使用,可以把多对一的Map反转为一对多的Multimap。


Map<String, Integer> map = ImmutableMap.of("a", 1, "b", 1, "c", 2);
SetMultimap<String, Integer> multimap = Multimaps.forMap(map);
// multimap:["a" => {1}, "b" => {1}, "c" => {2}]
Multimap<Integer, String> inverse = Multimaps.invertFrom(multimap, HashMultimap<Integer, String>.create());
// inverse:[1 => {"a","b"}, 2 => {"c"}]
包装器


Multimaps提供了传统的包装方法,以及让你选择Map和Collection类型以自定义Multimap实现的工具方法。


只读包装 Multimap ListMultimap SetMultimap SortedSetMultimap
同步包装 Multimap ListMultimap SetMultimap SortedSetMultimap
自定义实现 Multimap ListMultimap SetMultimap SortedSetMultimap
自定义Multimap的方法允许你指定Multimap中的特定实现。但要注意的是:


Multimap假设对Map和Supplier产生的集合对象有完全所有权。这些自定义对象应避免手动更新,并且在提供给Multimap时应该是空的,此外还不应该使用软引用、弱引用或虚引用。
无法保证修改了Multimap以后,底层Map的内容是什么样的。
即使Map和Supplier产生的集合都是线程安全的,它们组成的Multimap也不能保证并发操作的线程安全性。并发读操作是工作正常的,但需要保证并发读写的话,请考虑用同步包装器解决。
只有当Map、Supplier、Supplier产生的集合对象、以及Multimap存放的键值类型都是可序列化的,Multimap才是可序列化的。
Multimap.get(key)返回的集合对象和Supplier返回的集合对象并不是同一类型。但如果Supplier返回的是随机访问集合,那么Multimap.get(key)返回的集合也是可随机访问的。
请注意,用来自定义Multimap的方法需要一个Supplier参数,以创建崭新的集合。下面有个实现ListMultimap的例子——用TreeMap做映射,而每个键对应的多个值用LinkedList存储。


ListMultimap<String, Integer> myMultimap = Multimaps.newListMultimap(
    Maps.<String, Collection>newTreeMap(),
    new Supplier<LinkedList>() {
        public LinkedList get() {
            return Lists.newLinkedList();
        }
    });
Tables
Tables类提供了若干称手的工具方法。


  • 自定义Table


堪比Multimaps.newXXXMultimap(Map, Supplier)工具方法,Tables.newCustomTable(Map, Supplier<Map>)允许你指定Table用什么样的map实现行和列。


// 使用LinkedHashMaps替代HashMaps
Table<String, Character, Integer> table = Tables.newCustomTable(
Maps.<String, Map<Character, Integer>>newLinkedHashMap(),
new Supplier<Map<Character, Integer>> () {
public Map<Character, Integer> get() {
return Maps.newLinkedHashMap();
}
});
transpose


transpose(Table<R, C, V>)方法允许你把Table<C, R, V>转置成Table<R, C, V>。例如,如果你在用Table构建加权有向图,这个方法就可以把有向图反转。


  • 包装器


还有很多你熟悉和喜欢的Table包装类。然而,在大多数情况下还请使用ImmutableTable


Unmodifiable Table RowSortedTable





原文地址:https://www.cnblogs.com/LinkinPark/p/5233129.html