javaweb icon indicating copy to clipboard operation
javaweb copied to clipboard

guava学习

Open www1350 opened this issue 8 years ago • 0 comments

Optional

创建Optional实例(以下都是静态方法):

  • Optional.of(T) 创建指定引用的Optional实例,若引用为null则快速失败
  • Optional.absent() 创建引用缺失的Optional实例
  • Optional.fromNullable(T) 创建指定引用的Optional实例,若引用为null则表示缺失

用Optional实例查询引用(以下都是非静态方法):

  • boolean isPresent() 如果Optional包含非null的引用(引用存在),返回true
  • T get() 返回Optional所包含的引用,若引用缺失,则抛出java.lang.IllegalStateException
  • T or(T) 返回Optional所包含的引用,若引用缺失,返回指定的值
  • T orNull() 返回Optional所包含的引用,若引用缺失,返回null
  • Set<T> asSet() 返回Optional所包含引用的单例不可变集,如果引用存在,返回一个只有单一元素的集合,如果引用缺失,返回一个空集合。

参考:http://ifeve.com/google-guava-using-and-avoiding-null/

        String a = null;
//Optional.of(null); 报错
        Optional<String> op1 = Optional.of("aa");
        Assert.assertTrue(op1.isPresent());
        Optional<String> op2 = Optional.fromNullable(a);
        Assert.assertFalse(op2.isPresent());
        Optional<String> op3 = Optional.absent();
        Assert.assertFalse(op3.isPresent());

        String aa = op1.get();
        Assert.assertEquals(aa,"aa");

        String aOr = op2.or("a");
        Assert.assertEquals(aOr,"a");

        String aNu = op3.orNull();
        Assert.assertNull(aNu);

        Set<String> set = op1.asSet();
        Assert.assertEquals(set.size(),1);

Preconditions

方法声明(不包括额外参数) 描述 检查失败时抛出的异常

  • checkArgument(boolean) 检查boolean是否为true,用来检查传递给方法的参数。
  • IllegalArgumentException
  • checkNotNull(T) 检查value是否为null,该方法直接返回value,因此可以内嵌使用checkNotNull。 NullPointerException
  • checkState(boolean) 用来检查对象的某些状态。 IllegalStateException
  • checkElementIndex(int index, int size) 检查index作为索引值对某个列表、字符串或数组是否有效。index>=0 && index<size * IndexOutOfBoundsException
  • checkPositionIndex(int index, int size) 检查index作为位置值对某个列表、字符串或数组是否有效。index>=0 && index<=size * IndexOutOfBoundsException
  • checkPositionIndexes(int start, int end, int size) 检查[start, end]表示的位置范围对某个列表、字符串或数组是否有效* IndexOutOfBoundsException
        int i=1;
        checkArgument(i >= 0, "Argument was %s but expected nonnegative", i);
        checkNotNull(i);
        checkState(true);
        checkElementIndex(2,4);
        checkPositionIndexes(0,8,4);

Objects

    class  Person implements Comparable<Person>{
        private String name;
        private String password;

        public Person(String name, String password) {
            this.name = name;
            this.password = password;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        @Override
        public String toString() {
            return MoreObjects.toStringHelper(this)
                    .add("name", name)
                    .add("password", password)
                    .toString();
        }

        @Override
        public int hashCode() {
            return Objects.hashCode(name,password);
        }

        @Override
        public boolean equals(Object obj) {
            if(obj instanceof  Person){
                Person x = (Person) obj;
                return Objects.equal(name,x.name) && Objects.equal(password, x.password);
            }
            return false;
        }

        @Override
        public int compareTo(Person o) {
            return ComparisonChain.start()
                    .compare(this.name,o.name)
                    .compare(this.password,o.password)
                    .result();
        }
    }

Ordering

方法 描述

  • natural() 对可排序类型做自然排序,如数字按大小,日期按先后排序
  • usingToString() 按对象的字符串形式做字典排序[lexicographical ordering]
  • from(Comparator) 把给定的Comparator转化为排序器
  • reverse() 获取语义相反的排序器
  • nullsFirst() 使用当前排序器,但额外把null值排到最前面。
  • nullsLast() 使用当前排序器,但额外把null值排到最后面。
  • compound(Comparator) 合成另一个比较器,以处理当前排序器中的相等情况。
  • lexicographical() 基于处理类型T的排序器,返回该类型的可迭代对象Iterable<T>的排序器。
  • onResultOf(Function) 对集合中元素调用Function,再按返回值用当前排序器排序。
  • greatestOf(Iterable iterable, int k) 获取可迭代对象中最大的k个元素。 leastOf
  • isOrdered(Iterable) 判断可迭代对象是否已按排序器排序:允许有排序值相等的元素。 isStrictlyOrdered
  • sortedCopy(Iterable) 判断可迭代对象是否已严格按排序器排序:不允许排序值相等的元素。 immutableSortedCopy
  • min(E, E) 返回两个参数中最小的那个。如果相等,则返回第一个参数。 max(E, E)
  • min(E, E, E, E...) 返回多个参数中最小的那个。如果有超过一个参数都最小,则返回第一个最小的参数。 max(E, E, E, E...)
  • min(Iterable) 返回迭代器中最小的元素。如果可迭代对象中没有元素,则抛出NoSuchElementException。 max(Iterable), min(Iterator), max(Iterator)
        List<String> list = Lists.newArrayList();
        list.add("peida");
        list.add("jerry");
        list.add("harry");
        list.add("eva");
        list.add("jhon");
        list.add("neron");
        System.out.println("list:"+ list);
        Ordering<String> naturalOrdering = Ordering.natural();
        Ordering<Object> usingToStringOrdering = Ordering.usingToString();
        Ordering<Object> arbitraryOrdering = Ordering.arbitrary();

        System.out.println("naturalOrdering:"+ naturalOrdering.sortedCopy(list));
        System.out.println("usingToStringOrdering:"+ usingToStringOrdering.sortedCopy(list));
        System.out.println("arbitraryOrdering:"+ arbitraryOrdering.sortedCopy(list));

Throwables

  • RuntimeException propagate(Throwable) 如果Throwable是Error或RuntimeException,直接抛出;否则把Throwable包装成RuntimeException抛出。返回类型是RuntimeException,所以你可以像上面说的那样写成throw Throwables.propagate(t),Java编译器会意识到这行代码保证抛出异常。
  • void propagateIfInstanceOf( Throwable, Class<X extends Exception>) throws X Throwable类型为X才抛出
  • void propagateIfPossible( Throwable) Throwable类型为Error或RuntimeException才抛出
  • void propagateIfPossible( Throwable, Class<X extends Throwable>) throws X Throwable类型为X, Error或RuntimeException才抛出

http://ifeve.com/google-guava-throwables/

不可变集合

可变集合接口 属于JDK还是Guava 不可变版本

  • Collection JDK ImmutableCollection
  • List JDK ImmutableList
  • Set JDK ImmutableSet
  • SortedSet/NavigableSet JDK ImmutableSortedSet
  • Map JDK ImmutableMap
  • SortedMap JDK ImmutableSortedMap
  • Multiset Guava ImmutableMultiset
  • SortedMultiset Guava ImmutableSortedMultiset
  • Multimap Guava ImmutableMultimap
  • ListMultimap Guava ImmutableListMultimap
  • SetMultimap Guava ImmutableSetMultimap
  • BiMap Guava ImmutableBiMap
  • ClassToInstanceMap Guava ImmutableClassToInstanceMap
  • Table Guava ImmutableTable
         final ImmutableSet<String> COLOR_NAMES = ImmutableSet.of(
                "red",
                "orange",
                "yellow",
                "green",
                "blue",
                "purple");
        ImmutableSortedSet<String> a = ImmutableSortedSet.of("a", "b", "c", "a", "d", "b");
        System.out.println(a.toString());
        ImmutableList<String> defensiveCopy = ImmutableList.copyOf(COLOR_NAMES);
        System.out.println(defensiveCopy.toString());

newcollectiontypes

Multiset

Guava提供了一个新集合类型 Multiset,它可以多次添加相等的元素。维基百科从数学角度这样定义Multiset:”集合[set]概念的延伸,它的元素可以重复出现…与集合[set]相同而与元组[tuple]相反的是,Multiset元素的顺序是无关紧要的:Multiset {a, a, b}和{a, b, a}是相等的”。——译者注:这里所说的集合[set]是数学上的概念,Multiset继承自JDK中的Collection接口,而不是Set接口,所以包含重复元素并没有违反原有的接口契约。

可以用两种方式看待Multiset:

  1. 没有元素顺序限制的ArrayList<E>
  2. Map<E, Integer>,键为元素,值为计数

Guava的Multiset API也结合考虑了这两种方式: 当把Multiset看成普通的Collection时,它表现得就像无序的ArrayList:

  1. add(E)添加单个给定元素
  2. iterator()返回一个迭代器,包含Multiset的所有元素(包括重复的元素)
  3. size()返回所有元素的总个数(包括重复的元素)

当把Multiset看作Map<E, Integer>时,它也提供了符合性能期望的查询操作:

  1. count(Object)返回给定元素的计数。HashMultiset.count的复杂度为O(1),TreeMultiset.count的复杂度为O(log n)。
  2. entrySet()返回Set<Multiset.Entry<E>>,和Map的entrySet类似。
  3. elementSet()返回所有不重复元素的Set<E>,和Map的keySet()类似。
  4. 所有Multiset实现的内存消耗随着不重复元素的个数线性增长。

方法 描述

  • count(E) 给定元素在Multiset中的计数
  • elementSet() Multiset中不重复元素的集合,类型为Set<E>
  • entrySet() 和Map的entrySet类似,返回Set<Multiset.Entry<E>>,其中包含的Entry支持getElement()和getCount()方法
  • add(E, int) 增加给定元素在Multiset中的计数
  • remove(E, int) 减少给定元素在Multiset中的计数
  • setCount(E, int) 设置给定元素在Multiset中的计数,不可以为负数
  • size() 返回集合元素的总个数(包括重复的元素)
  • Map 对应的Multiset 是否支持null元素
  • HashMap HashMultiset 是
  • TreeMap TreeMultiset 是(如果comparator支持的话)
  • LinkedHashMap LinkedHashMultiset 是
  • ConcurrentHashMap ConcurrentHashMultiset 否
  • ImmutableMap ImmutableMultiset 否

SortedMultiset

  1. SortedMultiset是Multiset 接口的变种,它支持高效地获取指定范围的子集。比方说,你可以用 latencies.subMultiset(0,BoundType.CLOSED, 100, BoundType.OPEN).size()来统计你的站点中延迟在100毫秒以内的访问,然后把这个值和latencies.size()相比,以获取这个延迟水平在总体访问中的比例。
  2. TreeMultiset实现SortedMultiset接口。在撰写本文档时,ImmutableSortedMultiset还在测试和GWT的兼容性。

Multimap

每个有经验的Java程序员都在某处实现过Map<K, List<V>>或Map<K, Set<V>>,并且要忍受这个结构的笨拙。例如,Map<K, Set<V>>通常用来表示非标定有向图。Guava的 Multimap可以很容易地把一个键映射到多个值。换句话说,Multimap是把键映射到任意多个值的一般方式。

可以用两种方式思考Multimap的概念:”键-单个值映射”的集合: a -> 1 a -> 2 a ->4 b -> 3 c -> 5

或者”键-值集合映射”的映射: a -> [1, 2, 4] b -> 3 c -> 5

一般来说,Multimap接口应该用第一种方式看待,但asMap()视图返回Map<K, Collection<V>>,让你可以按另一种方式看待Multimap。重要的是,不会有任何键映射到空集合:一个键要么至少到一个值,要么根本就不在Multimap中。

很少会直接使用Multimap接口,更多时候你会用ListMultimap或SetMultimap接口,它们分别把键映射到List或Set。

方法签名 描述 等价于

  • put(K, V) 添加键到单个值的映射 multimap.get(key).add(value)
  • putAll(K, Iterable<V>) 依次添加键到多个值的映射 Iterables.addAll(multimap.get(key), values)
  • remove(K, V) 移除键到值的映射;如果有这样的键值并成功移除,返回true。 multimap.get(key).remove(value)
  • removeAll(K) 清除键对应的所有值,返回的集合包含所有之前映射到K的值,但修改这个集合就不会影响Multimap了。 multimap.get(key).clear()
  • replaceValues(K, Iterable<V>) 清除键对应的所有值,并重新把key关联到Iterable中的每个元素。返回的集合包含所有之前映射到K的值。 multimap.get(key).clear(); Iterables.addAll(multimap.get(key), values)
  • 实现 键行为类似 值行为类似
  • ArrayListMultimap HashMap ArrayList
  • HashMultimap HashMap HashSet
  • LinkedListMultimap* LinkedHashMap* LinkedList*
  • LinkedHashMultimap** LinkedHashMap LinkedHashMap
  • TreeMultimap TreeMap TreeSet
  • ImmutableListMultimap ImmutableMap ImmutableList
  • ImmutableSetMultimap ImmutableMap ImmutableSet

Multimap还支持若干强大的视图:

  • asMap为Multimap<K, V>提供Map<K,Collection<V>>形式的视图。返回的Map支持remove操作,并且会反映到底层的Multimap,但它不支持put或putAll操作。更重要的是,如果你想为Multimap中没有的键返回null,而不是一个新的、可写的空集合,你就可以使用asMap().get(key)。(你可以并且应当把asMap.get(key)返回的结果转化为适当的集合类型——如SetMultimap.asMap.get(key)的结果转为Set,ListMultimap.asMap.get(key)的结果转为List——Java类型系统不允许ListMultimap直接为asMap.get(key)返回List——译者注:也可以用Multimaps中的asMap静态方法帮你完成类型转换)
  • entries用Collection<Map.Entry<K, V>>返回Multimap中所有”键-单个值映射”——包括重复键。(对SetMultimap,返回的是Set)
  • keySet用Set表示Multimap中所有不同的键。
  • keys用Multiset表示Multimap中的所有键,每个键重复出现的次数等于它映射的值的个数。可以从这个Multiset中移除元素,但不能做添加操作;移除操作会反映到底层的Multimap。
  • values()用一个”扁平”的Collection<V>包含Multimap中的所有值。这有一点类似于Iterables.concat(multimap.asMap().values()),但它直接返回了单个Collection,而不像multimap.asMap().values()那样是按键区分开的Collection。

BiMap

传统上,实现键值对的双向映射需要维护两个单独的map,并保持它们间的同步。但这种方式很容易出错,而且对于值已经在map中的情况,会变得非常混乱。例如:

Map<String, Integer> nameToId = Maps.newHashMap();
Map<Integer, String> idToName = Maps.newHashMap();

nameToId.put("Bob", 42);
idToName.put(42, "Bob");
//如果"Bob"和42已经在map中了,会发生什么?
//如果我们忘了同步两个map,会有诡异的bug发生...

BiMap<K, V>是特殊的Map:

  • 可以用 inverse()反转BiMap<K, V>的键值映射
  • 保证值是唯一的,因此 values()返回Set而不是普通的Collection
  • 在BiMap中,如果你想把键映射到已经存在的值,会抛出IllegalArgumentException异常。如果对特定值,你想要强制替换它的键,请使用 BiMap.forcePut(key, value)。
BiMap<String, Integer> userId = HashBiMap.create();
String userForId = userId.inverse().get(id);

键–值实现 值–键实现 对应的BiMap实现

  • HashMap HashMap HashBiMap
  • ImmutableMap ImmutableMap ImmutableBiMap
  • EnumMap EnumMap EnumBiMap
  • EnumMap HashMap EnumHashBiMap

Table

Table<Vertex, Vertex, Double> weightedGraph = HashBasedTable.create();
weightedGraph.put(v1, v2, 4);
weightedGraph.put(v1, v3, 20);
weightedGraph.put(v2, v3, 5);

weightedGraph.row(v1); // returns a Map mapping v2 to 4, v3 to 20
weightedGraph.column(v3); // returns a Map mapping v1 to 20, v2 to 5

通常来说,当你想使用多个键做索引的时候,你可能会用类似Map<FirstName, Map<LastName, Person>>的实现,这种方式很丑陋,使用上也不友好。Guava为此提供了新集合类型Table,它有两个支持所有类型的键:”行”和”列”。Table提供多种视图,以便你从各种角度使用它:

  • rowMap():用Map<R, Map<C, V>>表现Table<R, C, V>。同样的, rowKeySet()返回”行”的集合Set<R>。
  • row(r) :用Map<C, V>返回给定”行”的所有列,对这个map进行的写操作也将写入Table中。
  • 类似的列访问方法:columnMap()、columnKeySet()、column(c)。(基于列的访问会比基于的行访问稍微低效点)
  • cellSet():用元素类型为Table.Cell<R, C, V>的Set表现Table<R, C, V>。Cell类似于Map.Entry,但它是用行和列两个键区分的。

Table有如下几种实现:

  1. HashBasedTable:本质上用HashMap<R, HashMap<C, V>>实现;
  2. TreeBasedTable:本质上用TreeMap<R, TreeMap<C,V>>实现;
  3. ImmutableTable:本质上用ImmutableMap<R, ImmutableMap<C, V>>实现;注:ImmutableTable对稀疏或密集的数据集都有优化。
  4. ArrayTable:要求在构造时就指定行和列的大小,本质上由一个二维数组实现,以提升访问速度和密集Table的内存利用率。ArrayTable与其他Table的工作原理有点不同,请参见Javadoc了解详情。

ClassToInstanceMap

RangeSet

RangeSet<Integer> rangeSet = TreeRangeSet.create();
rangeSet.add(Range.closed(1, 10)); // {[1,10]}
rangeSet.add(Range.closedOpen(11, 15));//不相连区间:{[1,10], [11,15)}
rangeSet.add(Range.closedOpen(15, 20)); //相连区间; {[1,10], [11,20)}
rangeSet.add(Range.openClosed(0, 0)); //空区间; {[1,10], [11,20)}
rangeSet.remove(Range.open(5, 10)); //分割[1, 10]; {[1,5], [10,10], [11,20)}

RangeSet的视图

RangeSet的实现支持非常广泛的视图:

  • complement():返回RangeSet的补集视图。complement也是RangeSet类型,包含了不相连的、非空的区间。
  • subRangeSet(Range<C>):返回RangeSet与给定Range的交集视图。这扩展了传统排序集合中的headSet、subSet和tailSet操作。
  • asRanges():用Set<Range<C>>表现RangeSet,这样可以遍历其中的Range。
  • asSet(DiscreteDomain<C>)(仅ImmutableRangeSet支持):用ImmutableSortedSet<C>表现RangeSet,以区间中所有元素的形式而不是区间本身的形式查看。(这个操作不支持DiscreteDomain 和RangeSet都没有上边界,或都没有下边界的情况)
  • RangeSet的查询方法

为了方便操作,RangeSet直接提供了若干查询方法,其中最突出的有:

  • contains(C):RangeSet最基本的操作,判断RangeSet中是否有任何区间包含给定元素。
  • rangeContaining(C):返回包含给定元素的区间;若没有这样的区间,则返回null。
  • encloses(Range<C>):简单明了,判断RangeSet中是否有任何区间包括给定区间。
  • span():返回包括RangeSet中所有区间的最小区间。

RangeMap

RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
rangeMap.put(Range.closed(1, 10), "foo"); //{[1,10] => "foo"}
rangeMap.put(Range.open(3, 6), "bar"); //{[1,3] => "foo", (3,6) => "bar", [6,10] => "foo"}
rangeMap.put(Range.open(10, 20), "foo"); //{[1,3] => "foo", (3,6) => "bar", [6,10] => "foo", (10,20) => "foo"}
rangeMap.remove(Range.closed(5, 11)); //{[1,3] => "foo", (3,5) => "bar", (11,20) => "foo"}
  • asMapOfRanges():用Map<Range<K>, V>表现RangeMap。这可以用来遍历RangeMap。
  • subRangeMap(Range<K>):用RangeMap类型返回RangeMap与给定Range的交集视图。这扩展了传统的headMap、subMap和tailMap操作。

强大的集合工具类

集合接口 属于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
List<TypeThatsTooLongForItsOwnGood> list = Lists.newArrayList();
Map<KeyType, LongishValueType> map = Maps.newLinkedHashMap();
List<Type> exactly100 = Lists.newArrayListWithCapacity(100);
List<Type> approx100 = Lists.newArrayListWithExpectedSize(100);
Set<Type> approx100Set = Sets.newHashSetWithExpectedSize(100);;
Multiset<String> multiset = HashMultiset.create();

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)

方法 类似的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()
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不是单元素集,就会出错了!

FluentIterable

Lists

方法 描述

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}}

Sets

  • 直接当作Set使用,因为SetView也实现了Set接口;
  • 用copyInto(Set)拷贝进另一个可变集合;
  • 用immutableCopy()对自己做不可变拷贝。 方法
  • union(Set, Set)
  • intersection(Set, Set)
  • difference(Set, Set)
  • symmetricDifference(Set, Set)
  • cartesianProduct(List<Set>) 返回所有集合的笛卡儿积 cartesianProduct(Set...)
  • powerSet(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<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"}}

Maps

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();
        }
    });

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> right = ImmutableMap.of( "b", 2, "c", 3,"d",4);
        MapDifference<String, Integer> diff = Maps.difference(left, right);

       diff.entriesInCommon(); // {b=2, c=3}
        diff.entriesInCommon(); // {b=2, c=3}
         diff.entriesOnlyOnLeft(); // {a=1}
       diff.entriesOnlyOnRight(); // {d=4}

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

Multisets

方法 说明 和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的交集; 没有类似方法
  • copyHighestCountFirst(Multiset) 返回Multiset的不可变拷贝,并将元素按重复出现的次数做降序排列
  • unmodifiableMultiset(Multiset) 返回Multiset的只读视图
  • unmodifiableSortedMultiset(SortedMultiset) 返回SortedMultiset的只读视图
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

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

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

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

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

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"}
*/


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"}
*/

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"}]

包装器

只读包装 Multimap ListMultimap SetMultimap SortedSetMultimap 同步包装 Multimap ListMultimap SetMultimap SortedSetMultimap 自定义实现 Multimap ListMultimap SetMultimap SortedSetMultimap

Tables

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

Unmodifiable Table RowSortedTable

缓存

LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
        .maximumSize(1000)
        .expireAfterWrite(10, TimeUnit.MINUTES)
        .removalListener(MY_LISTENER)
        .build(
            new CacheLoader<Key, Graph>() {
                public Graph load(Key key) throws AnyException {
                    return createExpensiveGraph(key);
                }
        });

Guava Cache与ConcurrentMap很相似,但也不完全一样。最基本的区别是ConcurrentMap会一直保存所有添加的元素,直到显式地移除。相对地,Guava Cache为了限制内存占用,通常都设定为自动回收元素。在某些场景下,尽管LoadingCache 不回收元素,它也是很有用的,因为它会自动加载缓存。

通常来说,Guava Cache适用于:

  • 你愿意消耗一些内存空间来提升速度。
  • 你预料到某些键会被查询一次以上。
  • 缓存中存放的数据总量不会超出内存容量。(Guava Cache是单个应用运行时的本地缓存。它不把数据存放到文件或外部服务器。如果这不符合你的需求,请尝试Memcached这类工具)

CacheLoader

LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
        .maximumSize(1000)
        .build(
            new CacheLoader<Key, Graph>() {
                public Graph load(Key key) throws AnyException {
                    return createExpensiveGraph(key);
                }
            });
...
try {
    return graphs.get(key);
} catch (ExecutionException e) {
    throw new OtherException(e.getCause());
}
LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
        .expireAfterAccess(10, TimeUnit.MINUTES)
        .build(
            new CacheLoader<Key, Graph>() {
                public Graph load(Key key) { // no checked exception
                    return createExpensiveGraph(key);
                }
            });
...
return graphs.getUnchecked(key);

Callable

Cache<Key, Graph> cache = CacheBuilder.newBuilder()
        .maximumSize(1000)
        .build(); // look Ma, no CacheLoader
...
try {
    // If the key wasn't in the "easy to compute" group, we need to
    // do things the hard way.
    cache.get(key, new Callable<Key, Graph>() {
        @Override
        public Value call() throws AnyException {
            return doThingsTheHardWay(key);
        }
    });
} catch (ExecutionException e) {
    throw new OtherException(e.getCause());
}

缓存回收

一个残酷的现实是,我们几乎一定没有足够的内存缓存所有数据。你你必须决定:什么时候某个缓存项就不值得保留了?Guava Cache提供了三种基本的缓存回收方式:基于容量回收、定时回收和基于引用回收。

基于容量的回收(size-based eviction)

  • 如果要规定缓存项的数目不超过固定值,只需使用CacheBuilder.maximumSize(long)。缓存将尝试回收最近没有使用或总体上很少使用的缓存项。——警告:在缓存项的数目达到限定值之前,缓存就可能进行回收操作——通常来说,这种情况发生在缓存项的数目逼近限定值时。
  • 另外,不同的缓存项有不同的“权重”(weights)——例如,如果你的缓存值,占据完全不同的内存空间,你可以使用CacheBuilder.weigher(Weigher)指定一个权重函数,并且用CacheBuilder.maximumWeight(long)指定最大总重。在权重限定场景中,除了要注意回收也是在重量逼近限定值时就进行了,还要知道重量是在缓存创建时计算的,因此要考虑重量计算的复杂度。

LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
        .maximumWeight(100000)
        .weigher(new Weigher<Key, Graph>() {
            public int weigh(Key k, Graph g) {
                return g.vertices().size();
            }
        })
        .build(
            new CacheLoader<Key, Graph>() {
                public Graph load(Key key) { // no checked exception
                    return createExpensiveGraph(key);
                }
            });

定时回收(Timed Eviction)

  1. expireAfterAccess(long, TimeUnit):缓存项在给定时间内没有被读/写访问,则回收。请注意这种缓存的回收顺序和基于大小回收一样。
  2. expireAfterWrite(long, TimeUnit):缓存项在给定时间内没有被写访问(创建或覆盖),则回收。如果认为缓存数据总是在固定时候后变得陈旧不可用,这种回收方式是可取的。

对定时回收进行测试时,不一定非得花费两秒钟去测试两秒的过期。你可以使用Ticker接口和CacheBuilder.ticker(Ticker)方法在缓存中自定义一个时间源,而不是非得用系统时钟。

基于引用的回收(Reference-based Eviction)

  • CacheBuilder.weakKeys():使用弱引用存储键。当键没有其它(强或软)引用时,缓存项可以被垃圾回收。因为垃圾回收仅依赖恒等式(==),使用弱引用键的缓存用==而不是equals比较键。
  • CacheBuilder.weakValues():使用弱引用存储值。当值没有其它(强或软)引用时,缓存项可以被垃圾回收。因为垃圾回收仅依赖恒等式(==),使用弱引用值的缓存用==而不是equals比较值。
  • CacheBuilder.softValues():使用软引用存储值。软引用只有在响应内存需要时,才按照全局最近最少使用的顺序回收。考虑到使用软引用的性能影响,我们通常建议使用更有性能预测性的缓存大小限定(见上文,基于容量回收)。使用软引用值的缓存同样用==而不是equals比较值。

显式清除

个别清除:Cache.invalidate(key) 批量清除:Cache.invalidateAll(keys) 清除所有缓存项:Cache.invalidateAll()

移除监听器

通过CacheBuilder.removalListener(RemovalListener),你可以声明一个监听器,以便缓存项被移除时做一些额外操作。缓存项被移除时,RemovalListener会获取移除通知[RemovalNotification],其中包含移除原因[RemovalCause]、键和值。

CacheLoader<Key, DatabaseConnection> loader = new CacheLoader<Key, DatabaseConnection> () {
    public DatabaseConnection load(Key key) throws Exception {
        return openConnection(key);
    }
};

RemovalListener<Key, DatabaseConnection> removalListener = new RemovalListener<Key, DatabaseConnection>() {
    public void onRemoval(RemovalNotification<Key, DatabaseConnection> removal) {
        DatabaseConnection conn = removal.getValue();
        conn.close(); // tear down properly
    }
};

return CacheBuilder.newBuilder()
    .expireAfterWrite(2, TimeUnit.MINUTES)
    .removalListener(removalListener)
    .build(loader);

刷新

刷新和回收不太一样。正如LoadingCache.refresh(K)所声明,刷新表示为键加载新值,这个过程可以是异步的。在刷新操作进行时,缓存仍然可以向其他线程返回旧值,而不像回收操作,读缓存的线程必须等待新值加载完成。 如果刷新过程抛出异常,缓存将保留旧值,而异常会在记录到日志后被丢弃[swallowed]。 重载CacheLoader.reload(K, V)可以扩展刷新时的行为,这个方法允许开发者在计算新值时使用旧的值。

//有些键不需要刷新,并且我们希望刷新是异步完成的
LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
        .maximumSize(1000)
        .refreshAfterWrite(1, TimeUnit.MINUTES)
        .build(
            new CacheLoader<Key, Graph>() {
                public Graph load(Key key) { // no checked exception
                    return getGraphFromDatabase(key);
                }

                public ListenableFuture<Key, Graph> reload(final Key key, Graph prevGraph) {
                    if (neverNeedsRefresh(key)) {
                        return Futures.immediateFuture(prevGraph);
                    }else{
                        // asynchronous!
                        ListenableFutureTask<Key, Graph> task=ListenableFutureTask.create(new Callable<Key, Graph>() {
                            public Graph call() {
                                return getGraphFromDatabase(key);
                            }
                        });
                        executor.execute(task);
                        return task;
                    }
                }
            });

统计

CacheBuilder.recordStats()用来开启Guava Cache的统计功能。统计打开后,Cache.stats()方法会返回CacheStats对象以提供如下统计信息:

  • hitRate():缓存命中率;
  • averageLoadPenalty():加载新值的平均时间,单位为纳秒;
  • evictionCount():缓存项被回收的总数,不包括显式清除。

www1350 avatar Sep 12 '16 02:09 www1350