二、2.3Guava的集合工具类

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

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

集合接口属于JDK还是Guava对应的Guava工具类
CollectionJDKCollections2:不要和java.util.Collections混淆
List JDKLists
SetJDKSets
SortedSetJDKSets
MapJDKMaps
SortedMapJDKMaps
QueueJDKQueues
MultisetGuavaMultisets
MultimapGuavaMultimaps
BiMapGuavaMaps
TableGuavaTables

静态工厂方法

Guava提供了能够推断范型的静态工厂方法:

List<TypeThatsTooLongForItsOwnGood> list = Lists.newArrayList();
Map<KeyType, LongishValueType> map = Maps.newLinkedHashMap();

但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);

Iterables

下面列出了一些最常用的工具方法

concat(Iterable)串联多个iterables的懒视图
frequency(Iterable, Object)返回对象在iterable中出现的次数
partition(Iterable, int)把iterable按指定大小分割,得到的子集都不能进行修改操作
getFirst(Iterable, T default)返回iterable的第一个元素,若iterable为空则返回默认值
getLast(Iterable)返回iterable的最后一个元素,若iterable为空则抛出NoSuchElementException
elementsEqual(Iterable, Iterable)如果两个iterable中的所有元素相等且顺序一致,返回true
unmodifiableIterable(Iterable)返回iterable的不可变视图 与Collections.
limit(Iterable, int)限制iterable的元素个数限制给定值
getOnlyElement(Iterable)获取iterable中唯一的元素,如果iterable为空或有多个元素,则快速失败
package collection.collections;

import com.google.common.collect.Iterables;
import com.google.common.primitives.Ints;
import org.junit.Test;

import java.util.List;

/**
 * Created by LF on 2017/4/24.
 */
public class ConllectionsTest {
    @Test
    public void collection() {
        List<Integer> integers = Ints.asList(1, 2, 3);
        List<Integer> integers1 = Ints.asList(4, 5, 6);
        Iterable<Integer> concatenated = Iterables.concat(integers, integers1); // concatenated包括元素 1, 2, 3, 4, 5, 6
        Iterables.elementsEqual(integers1,integers);
        int lastAdded = Iterables.getLast(concatenated);//返回iterable的第一个元素,若iterable为空则返回默认值
        int theElement = Iterables.getOnlyElement(concatenated);//返回iterable的最后一个元素,若iterable为空则抛出NoSuchElementException

    }
}

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

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)返回所有集合的笛卡儿积 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提供如下静态工厂方法:

具体实现类型工厂方法
HashSetbasic, with elements, from Iterable, with expected size, from Iterator
LinkedHashSetbasic, from Iterable, with expected size
TreeSetbasic, with Comparator, from Iterable

Maps

uniqueIndex

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

package collection.collections;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.junit.Test;

import java.util.List;

/**
 * Created by LF on 2017/4/24.
 */
public class MapsTest {
    @Test
    public void maps(){
        List<String> list = Lists.newArrayList("A","BA");
        ImmutableMap<Integer, String> uniqueIndex = Maps.uniqueIndex(list, String -> String.length());
        System.err.println(uniqueIndex.keySet());
    }
}

difference

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

12
entriesInCommon()两个Map中都有的映射项,包括匹配的键与值
entriesDiffering()键相同但是值不同值映射项。返回的Map的值类型为
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

提供如下静态工厂方法:

具体实现类型工厂方法
HashMapbasic, from Map, with expected size
LinkedHashMapbasic, from Map
TreeMapbasic, from Comparator, from SortedMap
EnumMapfrom Class, from Map
ConcurrentMap:支持所有操作 basic
IdentityHashMapbasic

Multisets

标准的Collection操作会忽略Multiset重复元素的个数,而只关心元素是否存在于Multiset中,如containsAll方法。为此,Multisets提供了若干方法,以顾及Multiset元素的重复性:

方法说明和Collection方法的区别
containsOccurrences(Multiset sup, Multiset sub)对任意o,如果sub.count(o)<=super.count(o),返回trueCollection.containsAll忽略个数,而只关心sub的元素是否都在super中
removeOccurrences(Multiset removeFrom, Multiset toRemove)对toRemove中的重复元素,仅在removeFrom中删除相同个数。Collection.removeAll移除所有出现在toRemove的元素
retainOccurrences(MultisetremoveFrom, 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

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实现。

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"}]
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值