1. 引言
本文是 Google Guava 库第 21 版新特性系列文章的第一篇。我们将讨论新增的类以及对之前版本的重大变更。
具体来说,我们会聚焦 common.collect
包中的新增功能和改进。
Guava 21 在 common.collect
包中引入了一些实用的新工具,下面快速了解这些工具以及如何充分利用它们。
2. Streams 类
Java 8 引入的 java.util.stream.Stream
让我们都很兴奋。现在 Guava 充分利用了流式 API,补充了标准库缺失的功能。
Streams
是一个静态工具类,提供了处理 Java 8 流的实用方法。
2.1 Streams.stream()
Streams
类提供了四种方式从 Iterable
、Iterator
、Optional
和 Collection
创建流。
⚠️ 注意:通过 Collection
创建流的方法已被弃用,因为 Java 8 已原生支持:
List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Stream<Integer> streamFromCollection = Streams.stream(numbers);
Stream<Integer> streamFromIterator = Streams.stream(numbers.iterator());
Stream<Integer> streamFromIterable = Streams.stream((Iterable<Integer>) numbers);
Stream<Integer> streamFromOptional = Streams.stream(Optional.of(1));
Streams
类还提供了 OptionalDouble
、OptionalLong
和 OptionalInt
的重载版本。这些方法返回仅包含该元素的流(如果存在),否则返回空流:
LongStream streamFromOptionalLong = Streams.stream(OptionalLong.of(1));
IntStream streamFromOptionalInt = Streams.stream(OptionalInt.of(1));
DoubleStream streamFromOptionalDouble = Streams.stream(OptionalDouble.of(1.0));
2.2 Streams.concat()
Streams
类提供了合并多个同类型流的方法:
Stream<Integer> concatenatedStreams = Streams.concat(streamFromCollection, streamFromIterable,streamFromIterator);
concat
方法还支持 LongStream
、IntStream
和 DoubleStream
的重载版本。
2.3 Streams.findLast()
通过 findLast()
方法可以快速获取流中的最后一个元素:
List<Integer> integers = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
Optional<Integer> lastItem = Streams.findLast(integers.stream());
如果流为空,返回 Optional.empty()
。该方法同样适用于 LongStream
、IntStream
和 DoubleStream
。
2.4 Streams.mapWithIndex()
使用 mapWithIndex()
方法时,流中的每个元素都会携带其位置(索引)信息:
mapWithIndex( Stream.of("a", "b", "c"), (str, index) -> str + ":" + index)
返回结果为 Stream.of("a:0","b:1","c:2")
。
通过重载的 mapWithIndex()
方法,IntStream
、LongStream
和 DoubleStream
也能实现相同功能。
2.5 Streams.zip()
使用 zip
方法可以将两个流中的对应元素通过指定函数映射:
Streams.zip(
Stream.of("candy", "chocolate", "bar"),
Stream.of("$1", "$2","$3"),
(arg1, arg2) -> arg1 + ":" + arg2
);
返回结果为 Stream.of("candy:$1","chocolate:$2","bar:$3")
。
✅ 结果流的长度等于两个输入流中较短的那个,较长流的剩余元素会被忽略。
3. Comparators 类
Guava 的 Ordering
类已被弃用,并将在新版本中移除。其大部分功能已被 JDK 8 的比较器替代。
Guava 新增的 Comparators
类提供了 Java 8 标准库尚未支持的 Ordering
高级功能。
3.1 Comparators.isInOrder()
该方法检查可迭代对象中的每个元素是否按 Comparator
指定的顺序大于或等于前一个元素:
List<Integer> integers = Arrays.asList(1,2,3,4,4,6,7,8,9,10);
boolean isInAscendingOrder = Comparators.isInOrder(
integers, new AscendingOrderComparator());
3.2 Comparators.isInStrictOrder()
与 isInOrder()
类似,但要求更严格:元素必须严格大于前一个元素(不能相等)。上面示例代码对此方法会返回 false
。
3.3 Comparators.lexicographical()
该 API 返回一个新的 Comparator
实例,按字典序(lexicographical)成对比较对应元素。内部实际创建了 LexicographicalOrdering<S>()
的实例。
4. MoreCollectors 类
MoreCollectors
包含一些 Java 8 java.util.stream.Collectors
未提供的实用收集器,且与 com.google.common
类型无关。
4.1 MoreCollectors.toOptional()
该收集器将包含零个或一个元素的流转换为 Optional
:
List<Integer> numbers = Arrays.asList(1);
Optional<Integer> number = numbers.stream()
.map(e -> e * 2)
.collect(MoreCollectors.toOptional());
❌ 如果流包含多个元素,会抛出 IllegalArgumentException
。
4.2 MoreCollectors.onlyElement()
该收集器从仅包含一个元素的流中提取该元素:
- 如果流包含多个元素 → 抛出
IllegalArgumentException
- 如果流为空 → 抛出
NoSuchElementException
5. Interners.InternerBuilder
这是 Guava 现有 Interners
的内部构建器类。它提供便捷方法定义 Interner
的并发级别和类型(弱引用或强引用):
Interners interners = Interners.newBuilder()
.concurrencyLevel(2)
.weak()
.build();
6. 总结
本文快速介绍了 Guava 21 中 common.collect
包的新增功能。这些工具类弥补了 Java 8 标准库的不足,提供了更简洁高效的流处理、比较和收集操作。
完整代码示例可在 GitHub 获取。