转载的,有问题请联系我

原文链接 译文链接 译者:沈义扬,校对:丁一

尚未完成: Queues, Tables工具类

任何对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之前,构造新的范型集合时要讨厌地重复声明范型:

1 List<TypeThatsTooLongForItsOwnGood> list = new ArrayList<TypeThatsTooLongForItsOwnGood>();

我想我们都认为这很讨厌。因此Guava提供了能够推断范型的静态工厂方法:

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

可以肯定的是,JDK7版本的钻石操作符(<>)没有这样的麻烦:

1 List<TypeThatsTooLongForItsOwnGood> list = new ArrayList<>();

但Guava的静态工厂方法远不止这么简单。用工厂方法模式,我们可以方便地在初始化时就指定起始元素。

1 Set<Type> copySet = Sets.newHashSet(elements);
2 List<String> theseElements = Lists.newArrayList("alpha""beta""gamma");

此外,通过为工厂方法命名(Effective Java第一条),我们可以提高集合初始化大小的可读性:

1 List<Type> exactly100 = Lists.newArrayListWithCapacity(100);
2 List<Type> approx100 = Lists.newArrayListWithExpectedSize(100);
3 Set<Type> approx100Set = Sets.newHashSetWithExpectedSize(100);

确切的静态工厂方法和相应的工具类一起罗列在下面的章节。

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

1 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中的元素,则不会对它进行串联操作。

1 Iterable<Integer> concatenated = Iterables.concat(
2         Ints.asList(123),
3         Ints.asList(456)); // concatenated包括元素 1, 2, 3, 4, 5, 6
4 String lastAdded = Iterables.getLast(myLinkedHashSet);
5 String theElement = Iterables.getOnlyElement(thisSetIsDefinitelyASingleton);
6 //如果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()
1 List countUp = Ints.asList(12345);
2 List countDown = Lists.reverse(theList); // {5, 4, 3, 2, 1}
3 List<List> parts = Lists.partition(countUp, 2);//{{1,2}, {3,4}, {5}}

静态工厂方法

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

具体实现类型 工厂方法
ArrayList basicwith elementsfrom Iterablewith exact capacitywith expected sizefrom Iterator
LinkedList basicfrom 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)

使用范例:

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

其他Set工具方法

方法 描述 另请参见
cartesianProduct(List<Set>) 返回所有集合的笛卡儿积 cartesianProduct(Set...)
powerSet(Set) 返回给定集合的所有子集  
1 Set<String> animals = ImmutableSet.of("gerbil""hamster");
2 Set<String> fruits = ImmutableSet.of("apple""orange""banana");
3  
4 Set<List<String>> product = Sets.cartesianProduct(animals, fruits);
5 // {{"gerbil", "apple"}, {"gerbil", "orange"}, {"gerbil", "banana"},
6 //  {"hamster", "apple"}, {"hamster", "orange"}, {"hamster", "banana"}}
7  
8 Set<Set<String>> animalSets = Sets.powerSet(animals);
9 // {{}, {"gerbil"}, {"hamster"}, {"gerbil", "hamster"}}

静态工厂方法

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

具体实现类型 工厂方法
HashSet basicwith elementsfrom Iterablewith expected sizefrom Iterator
LinkedHashSet basicfrom Iterablewith expected size
TreeSet basicwith Comparatorfrom Iterable

Maps

Maps类有若干值得单独说明的、很酷的方法。

uniqueIndex

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

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

1 ImmutableMap<Integer, String> stringsByIndex = Maps.uniqueIndex(strings,
2     new Function<String, Integer> () {
3         public Integer apply(String string) {
4             return string.length();
5         }
6     });

如果索引值不是独一无二的,请参见下面的Multimaps.index方法。

difference

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

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

处理BiMap的工具方法

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

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

静态工厂方法

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

具体实现类型 工厂方法
HashMap basicfrom Mapwith expected size
LinkedHashMap basicfrom Map
TreeMap basicfrom Comparatorfrom SortedMap
EnumMap from Classfrom 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的交集; 没有类似方法
01 Multiset<String> multiset1 = HashMultiset.create();
02 multiset1.add("a"2);
03  
04 Multiset<String> multiset2 = HashMultiset.create();
05 multiset2.add("a"5);
06  
07 multiset1.containsAll(multiset2); //返回true;因为包含了所有不重复元素,
08 //虽然multiset1实际上包含2个"a",而multiset2包含5个"a"
09 Multisets.containsOccurrences(multiset1, multiset2); // returns false
10  
11 multiset2.removeOccurrences(multiset1); // multiset2 现在包含3个"a"
12 multiset2.removeAll(multiset1);//multiset2移除所有"a",虽然multiset1只有2个"a"
13 multiset2.isEmpty(); // returns true

Multisets中的其他工具方法还包括:

copyHighestCountFirst(Multiset) 返回Multiset的不可变拷贝,并将元素按重复出现的次数做降序排列
unmodifiableMultiset(Multiset) 返回Multiset的只读视图
unmodifiableSortedMultiset(SortedMultiset) 返回SortedMultiset的只读视图
1 Multiset<String> multiset = HashMultiset.create();
2 multiset.add("a"3);
3 multiset.add("b"5);
4 multiset.add("c"1);
5  
6 ImmutableMultiset highestCountFirst = Multisets.copyHighestCountFirst(multiset);
7 //highestCountFirst,包括它的entrySet和elementSet,按{"b", "a", "c"}排列元素

Multimaps

Multimaps提供了若干值得单独说明的通用工具方法

index

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

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

01 ImmutableSet digits = ImmutableSet.of("zero""one""two""three""four""five""six""seven""eight""nine");
02 Function<String, Integer> lengthFunction = new Function<String, Integer>() {
03     public Integer apply(String string) {
04         return string.length();
05     }
06 };
07  
08 ImmutableListMultimap<Integer, String> digitsByLength= Multimaps.index(digits, lengthFunction);
09 /*
10 *  digitsByLength maps:
11 *  3 => {"one", "two", "six"}
12 *  4 => {"zero", "four", "five", "nine"}
13 *  5 => {"three", "seven", "eight"}
14 */

invertFrom

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

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

01 ArrayListMultimap<String, Integer> multimap = ArrayListMultimap.create();
02 multimap.putAll("b", Ints.asList(246));
03 multimap.putAll("a", Ints.asList(421));
04 multimap.putAll("c", Ints.asList(253));
05  
06 TreeMultimap<Integer, String> inverse = Multimaps.invertFrom(multimap, TreeMultimap<String, Integer>.create());
07 //注意我们选择的实现,因为选了TreeMultimap,得到的反转结果是有序的
08 /*
09 * inverse maps:
10 *  1 => {"a"}
11 *  2 => {"a", "b", "c"}
12 *  3 => {"c"}
13 *  4 => {"a", "b"}
14 *  5 => {"c"}
15 *  6 => {"b"}
16 */

forMap

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

1 Map<String, Integer> map = ImmutableMap.of("a"1"b"1"c"2);
2 SetMultimap<String, Integer> multimap = Multimaps.forMap(map);
3 // multimap:["a" => {1}, "b" => {1}, "c" => {2}]
4 Multimap<Integer, String> inverse = Multimaps.invertFrom(multimap, HashMultimap<Integer, String>.create());
5 // 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存储。

1 ListMultimap<String, Integer> myMultimap = Multimaps.newListMultimap(
2     Maps.<String, Collection>newTreeMap(),
3     new Supplier<LinkedList>() {
4         public LinkedList get() {
5             return Lists.newLinkedList();
6         }
7     });

Tables

Tables类提供了若干称手的工具方法。

自定义Table

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

1 // 使用LinkedHashMaps替代HashMaps
2 Table<String, Character, Integer> table = Tables.newCustomTable(
3 Maps.<String, Map<Character, Integer>>newLinkedHashMap(),
4 new Supplier<Map<Character, Integer>> () {
5 public Map<Character, Integer> get() {
6 return Maps.newLinkedHashMap();
7 }
8 });

transpose

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

包装器

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

Unmodifiable Table RowSortedTable

[Google Guava] 强大的集合工具类:java.util.Collections中未包含的集合工具的更多相关文章

  1. 005-guava 集合-集合工具类-java.util.Collections中未包含的集合工具[Maps,Lists,Sets],Iterables、Multisets、Multimaps、Tables

    一.概述 工具类与特定集合接口的对应关系归纳如下: 集合接口 属于JDK还是Guava 对应的Guava工具类 Collection JDK Collections2:不要和java.util.Col ...

  2. [Google Guava] 2.3-强大的集合工具类:java.util.Collections中未包含的集合工具

    原文链接 译文链接 译者:沈义扬,校对:丁一 尚未完成: Queues, Tables工具类 任何对JDK集合框架有经验的程序员都熟悉和喜欢java.util.Collections包含的工具方法.G ...

  3. 集合-强大的集合工具类:java.util.Collections中未包含的集合工具

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

  4. JavaSE-基础语法(二)-系统类(java.lang.*)和工具类(java.util.*)

    系统类(java.lang.*)和工具类(java.util.*) 一.系统类(java.lang.*) 这个包下包含java语言的核心类,如String.Math.System和Thread类等,使 ...

  5. 类 java.util.Collections 提供了对Set、List、Map进行排序、填充、查找元素的辅助方法。

      类 java.util.Collections 提供了对Set.List.Map进行排序.填充.查找元素的辅助方法. 1. void sort(List) //对List容器内的元素排序,排序的规 ...

  6. java.util.concurrent中的几种同步工具类

    java.util.concurrent并发包中提供了一系列的的同步工具类,这些基础类不管是否能在项目中使用到,了解一下使用方法和原理对java程序员来说都是有必要的.博主在看<java并发编程 ...

  7. JAVA核心技术I---JAVA基础知识(工具类Arrays和Collections类)

    一:工具类 –不存储数据,而是在数据容器上,实现高效操作 • 排序 • 搜索 –Arrays类 –Collection类 二:Arrays类(处理数组) (一)基本方法 –排序:对数组排序, sort ...

  8. java工具类之按对象中某属性排序

    import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang ...

  9. 集合框架的类和接口均在java.util包中。 任何对象加入集合类后,自动转变为Object类型,所以在取出的时候,需要进行强制类型转换。

    集合框架的类和接口均在java.util包中. 任何对象加入集合类后,自动转变为Object类型,所以在取出的时候,需要进行强制类型转换.

随机推荐

  1. python中的字典dict

    字典的常用操作及方法 增: dic[key]=value 有则修改,无则添加 dic.setdefault( ) 有则不变,无则添加:有键无值则值为None, 删:  dic.pop(key) 删除后 ...

  2. nginx安装目录文件

    nginx安装目录 conf 存放nginx的配置文件 在修改配置文件nginx.conf之前,一般先备份cp nginx.conf nginx.conf.bak html 存放前端文件的 默认带有首 ...

  3. Mac更新系统后提示xcrun error

    更新mac os后无法运行git,gcc等命令,出现missing xcrun错误. 这是因为更新系统后会卸载xcode,重新安装后会缺失xcode的命令行工具(command line tools) ...

  4. CF551B

    题目链接:http://codeforces.com/contest/551/problem/B 题目大意:给出字符串a, b, c.试图合理的安排a的字母顺序,使其中有尽可能多的与 c 或 b 相同 ...

  5. git rebase 还是 merge的使用场景最通俗的解释

    什么是 rebase? git rebase 你其实可以把它理解成是“重新设置基线”,将你的当前分支重新设置开始点.这个时候才能知道你当前分支于你需要比较的分支之间的差异. 原理很简单:rebase需 ...

  6. vue-codemirror + Java Compiler实现Java Web IDE

    背景 最近同事告诉我一个很有趣的需求:让用户(应用场景中,一般为其他开发者)自己填入Java代码片段,代码片段的内容为已经规定好的模板类的继承类,实现模板类定义的方法.我们的项目要实现动态编译代码片段 ...

  7. Understanding REST and RESTful APIs

    Understanding REST and RESTful APIs If you've spent any amount of time with modern web development, ...

  8. 怎样实现登录?| Cookie or JWT

    先问小伙伴们一个问题,登录难吗?"登录有什么难得?输入用户名和密码,后台检索出来,校验一下不就行了."凡是这样回答的小伙伴,你明显就是产品思维,登录看似简单,用户名和密码,后台校验 ...

  9. Java实现 LeetCode 685 冗余连接 II(并查集+有向图)

    685. 冗余连接 II 在本问题中,有根树指满足以下条件的有向图.该树只有一个根节点,所有其他节点都是该根节点的后继.每一个节点只有一个父节点,除了根节点没有父节点. 输入一个有向图,该图由一个有着 ...

  10. (Java实现) 洛谷 P1691 有重复元素的排列问题

    题目描述 设R={r1,r2,--,rn}是要进行排列的n个元素.其中元素r1,r2,--,rn可能相同.使设计一个算法,列出R的所有不同排列. 给定n以及待排列的n个元素.计算出这n个元素的所有不同 ...