Guava 解析
前言
Guava 本身适配不同的环境,Jdk 1.8 以上使用 jre flavor,Jdk 1.7 和 android 使用 android flavor。
类库的作者,不要使用 @Beta 成员,以后它们不会是 source-compatible。但我们可以使用其他成员,它们会是 binary-compatible,Guava 现在不会再因为非安全原因删除成员了,即使是 @Deprecated 的。
可用的功能见这个 User Guide。
common
Collect
不可变集合
Guava 提供了强类型的不可变集合,这些集合一旦创建就不能被修改,非常适合用于构建线程安全的应用和防御性编程。
1 | |
不可变集合的优势:
- 线程安全:多个线程可以安全地访问
- 防御性编程:防止外部代码修改内部数据
- 内存效率:可以使用更高效的数据结构表示
Collections(集合扩展)
Guava 的集合扩展是其最核心、最受欢迎的功能模块之一。它提供了不可变集合、新集合类型、集合工具类等丰富的功能,极大地简化了 Java 集合操作。
不可变集合
Multiset
Multiset 类似于 Java 的 Set,但它可以跟踪每个元素出现的次数。这使得它在需要计数的场景下非常实用。
1 | |
Multimap
这个数据结构首先是一个接口,有以下子接口: ListMultimap、SetMultimap。不同的子接口的 Get 方法返回不同的数据结构。
有两种方法可以理解这个数据结构:
1 | |
第一种形式同 Stream 的 groupingBy 的操作结果类似:
1 | |
第一种形式必须使用 asMap 创造一种视图,size 为 2。
1 | |
第二种形式本身属于天然形式,size 为 3(非 list 形式的,意味着 total entry count)。
所有的方法,都是视图方法:
- asMap(), mentioned above
- keys(), keySet(), values(), entries(), which are similar to the corresponding view collections of Map
- and, notably, even the collection returned by get(key) is an active view of the values corresponding to key 这一点很容易被忽略
Multimaps 是 Map<K, Collection
1 | |
BiMap(双向映射)
BiMap 是一种特殊的 Map,它保证值也是唯一的,并且可以通过值来查找键。
1 | |
Table(表格)
Table 是一种双键映射结构,类似于电子表格,使用行键和列键来定位值。
1 | |
RangeSet(区间集合)
RangeSet 用于管理一组不重叠的区间,非常适合处理时间范围、数值区间等问题。
1 | |
RangeMap(区间映射)
RangeMap 将区间映射到值,每个区间对应一个特定的值。
1 | |
集合工具类
Lists、Sets、Maps 工厂方法
Guava 提供了便捷的集合创建工厂方法。
1 | |
Iterables 和 Iterators
Iterables 提供了丰富的可迭代对象操作方法。
1 | |
Collections2.filter() 和 transform()
Collections2 提供了针对 Collection 的静态方法。
1 | |
与 Java 8 Stream API 的对比和互补
Guava 集合工具和 Java 8 Stream API 在功能上有重叠,但各有优势。
主要区别
| 特性 | Guava Collections | Java 8 Stream |
|---|---|---|
| 懒加载 | 否(立即执行) | 是(惰性求值) |
| 并行处理 | 有限 | 原生支持 |
| 不可变性 | 强类型支持 | 通过 Collectors |
| 新集合类型 | 丰富(Multiset、Multimap 等) | 无 |
| API 设计 | 方法链式 | 流式操作 |
互补使用场景
1 | |
选择建议
-
使用 Guava:
- 需要使用 Multiset、Multimap、BiMap、Table 等特殊集合类型
- 需要强类型的不可变集合
- 处理区间(RangeSet、RangeMap)
- 项目尚未升级到 Java 8
-
使用 Stream API:
- 需要复杂的数据转换和过滤
- 需要并行处理
- 需要惰性求值优化性能
-
结合使用:
- 使用 Stream 进行数据处理
- 使用 Guava 集合类型存储结果
- 使用 Guava 的不可变集合确保线程安全
实际使用建议
1. 优先使用不可变集合
1 | |
2. 合理选择集合类型
1 | |
3. 使用工厂方法简化代码
1 | |
4. 注意空值处理
1 | |
5. 性能考虑
1 | |
6. 防御性编程
1 | |
Guava Cache(缓存)
Guava Cache 是一个高性能、线程安全的本地缓存库,基于 ConcurrentHashMap 增强设计,提供了丰富的缓存配置和统计功能。
核心设计理念
Guava Cache 的核心设计包括:
- 线程安全:基于 ConcurrentHashMap 实现,支持高并发访问
- 自动驱逐:支持基于大小、时间、引用的自动驱逐策略
- 缓存加载:支持自动加载和手动加载两种模式
- 统计监控:Cache(缓存)
Guava Cache 是一个高性能的本地缓存库,基于 ConcurrentHashMap 进行增强,提供了自动加载、过期策略、驱逐监听等功能。
核心特性
核心 API
| API | 说明 |
|---|---|
CacheBuilder |
缓存构建器,链式配置缓存参数 |
LoadingCache |
自动加载缓存接口 |
CacheLoader |
缓存加载器,定义加载逻辑 |
Cache<K,V> |
手动缓存接口 |
CacheStats |
缓存统计信息 |
RemovalListener |
驱逐事件监听器 |
代码示例
1 | |
与 Caffeine 的对比
| 特性 | Guava Cache | Caffeine |
|---|---|---|
| 性能 | 高 | 更高(基于 W-TinyLFU 算法) |
| 异步加载 | 支持 | 支持,更完善 |
| 淘汰算法 | LRU | W-TinyLFU |
| 维护状态 | 基本维护 | 活跃维护 |
迁移建议:新项目建议使用 Caffeine,它是 Guava Cache 的改进版本,提供了更好的性能和更丰富的功能。
使用建议
- 合理设置过期时间:根据业务特点选择
expireAfterWrite或expireAfterAccess - 开启统计:生产环境建议开启统计,便于监控缓存效果
- 处理 null 值:使用
Optional包装 null 值,避免 NPE - 监控缓存:定期查看
CacheStats,优化缓存策略
Strings(字符串处理)
Guava 提供了强大的字符串处理工具类,简化了常见的字符串操作。
核心 API
| 工具类 | 主要功能 |
|---|---|
Strings |
基本字符串操作(空值处理、填充、重复等) |
Joiner |
字符串连接 |
Splitter |
字符串拆分 |
CharMatcher |
字符匹配和处理 |
CaseFormat |
命名风格转换 |
代码示例
1 | |
使用建议
- Joiner 和 Splitter 是不可变的:配置后可以重复使用,建议定义为常量
- 优先使用 CharMatcher:比正则表达式更简洁高效
- 处理 null 值:使用
Strings.nullToEmpty()避免 NPE - 批量操作:Joiner 和 Splitter 支持 List、Iterable 等集合类型
Preconditions(前置条件检查)
Guava 的 Preconditions 提供了简洁的前置条件检查工具,用于方法的输入验证和状态检查。
核心 API
| 方法 | 说明 | 抛出异常 |
|---|---|---|
checkArgument |
检查参数是否满足条件 | IllegalArgumentException |
checkNotNull |
检查引用是否为 null | NullPointerException |
checkState |
检查对象状态是否有效 | IllegalStateException |
checkElementIndex |
检查索引是否在集合范围内 | IndexOutOfBoundsException |
checkPositionIndex |
检查位置索引是否有效 | IndexOutOfBoundsException |
代码示例
1 | |
与其他方法的对比
| 方法 | Guava Preconditions | Java assert | Objects.requireNonNull |
|---|---|---|---|
| 异常类型 | 明确的异常类型 | AssertionError | NullPointerException |
| 编译检查 | 始终检查 | 需要开启 -ea | 始终检查 |
| 错误信息 | 支持格式化 | 不支持 | 固定格式 |
| 性能 | 最小化开销 | 零开销(关闭时) | 简单检查 |
使用建议
- 方法入口验证:在公共方法开始处使用
checkArgument验证参数 - 状态检查:在依赖对象状态的方法中使用
checkState - 非空检查:使用
checkNotNull替代手动 null 检查 - 清晰的错误信息:提供有意义的错误消息,便于调试
- 不要过度使用:只在真正需要验证的地方使用,避免影响性能
Optional(可选值)
Guava Optional 是一个用于表示可能为 null 的值的容器类,帮助开发者避免 NPE。
核心 API
| 方法 | 说明 |
|---|---|
of(T) |
创建包含非 null 值的 Optional |
absent() |
创建空的 Optional |
fromNullable(T) |
创建可能为 null 的 Optional |
isPresent() |
检查是否包含值 |
get() |
获取值(如果不存在抛出异常) |
or(T) |
获取值,不存在则返回默认值 |
orNull() |
获取值,不存在则返回 null |
transform(Function) |
转换值 |
Guava Optional vs Java 8 Optional
| 特性 | Guava Optional | Java 8 Optional |
|---|---|---|
| 包路径 | com.google.common.base |
java.util |
or() 方法 |
支持 | 不支持(用 orElse()) |
orNull() |
支持 | 不支持 |
transform() |
支持 | 用 map() |
| 序列化 | 支持 | 不支持 |
| 推荐使用 | Java 7 项目 | Java 8+ 项目 |
代码示例
1 | |
迁移建议
- Java 8+ 项目:优先使用
java.util.Optional - 需要序列化:使用 Guava Optional
- 需要
orNull()方法:使用 Guava Optional - 迁移路径:
1
2
3
4
5
6
7
8
9
10// Guava Optional
Optional<String> guavaOpt = Optional.fromNullable(value);
// 迁移到 Java 8 Optional
java.util.Optional<String> javaOpt = java.util.Optional.ofNullable(value);
// 主要差异
// guavaOpt.or(default) -> javaOpt.orElse(default)
// guavaOpt.orNull() -> javaOpt.orElse(null)
// guavaOpt.transform() -> javaOpt.map()
使用建议
- 不要将 Optional 作为字段类型:主要用于方法返回值
- 不要将 Optional 作为方法参数:直接传递 null 或使用重载
- 不要直接调用
get():先检查isPresent()或使用or() - 用于返回值:明确表示可能返回 null 的方法
Ordering(排序器)
Guava Ordering 是一个强大的排序工具类,提供了丰富的链式排序 API。
核心 API
| 方法 | 说明 |
|---|---|
natural() |
自然排序 |
usingToString() |
按 toString() 排序 |
from(Comparator) |
从 Comparator 创建 Ordering |
reverse() |
反转排序 |
nullsFirst() |
null 排在前面 |
nullsLast() |
null 排在后面 |
compound(Comparator) |
组合排序 |
onResultOf(Function) |
基于函数值排序 |
greatestOf(Iterable, n) |
获取最大的 n 个元素 |
leastOf(Iterable, n) |
获取最小的 n 个元素 |
代码示例
1 | |
与 Java 8 Comparator 的对比
| 特性 | Guava Ordering | Java 8 Comparator |
|---|---|---|
| 链式 API | 丰富 | 支持(thenComparing) |
| null 处理 | nullsFirst()/nullsLast() |
Comparator.nullsFirst() |
| 获取前 N 个 | greatestOf()/leastOf() |
Stream.sorted().limit() |
| 检查排序 | isOrdered() |
无直接方法 |
| 二分查找 | binarySearch() |
Collections.binarySearch() |
使用建议
- Java 8+ 项目:优先使用 Stream API 和 Comparator
- 复杂排序:使用
compound()组合多个排序条件 - null 处理:使用
nullsFirst()或nullsLast()避免 NPE - 性能优化:使用
greatestOf()/leastOf()比先排序再取更高效
EventBus(事件总线)
Guava EventBus 是一个发布-订阅模式的事件总线,实现了组件间的松耦合通信。
核心 API
| 类/接口 | 说明 |
|---|---|
EventBus |
同步事件总线 |
AsyncEventBus |
异步事件总线 |
@Subscribe |
订阅者方法注解 |
DeadEvent |
无订阅者的事件包装类 |
代码示例
1 | |
与 Spring Event 的对比
| 特性 | Guava EventBus | Spring Event |
|---|---|---|
| 依赖 | 无依赖 | 需要 Spring 框架 |
| 同步/异步 | 两者都支持 | 两者都支持 |
| 事务 | 不支持 | 支持(@TransactionalEventListener) |
| 条件订阅 | 不支持 | 支持(SpEL 表达式) |
| 泛型支持 | 支持 | 支持 |
| 使用场景 | 轻量级、无 Spring 环境 | Spring 项目 |
适用场景
适合使用 EventBus:
- 组件间需要解耦通信
- 不需要事务支持
- 轻量级项目,不依赖 Spring
- 简单的发布-订阅模式
不适合使用 EventBus:
- 需要事务支持的事件
- 需要条件过滤的事件
- 需要有序处理的事件
- 复杂的企业级应用(建议使用 Spring Event 或消息队列)
使用建议
- 事件对象不可变:确保事件对象在发布后不被修改
- 避免阻塞:同步事件总线中,订阅者方法不应长时间阻塞
- 异常处理:订阅者方法中的异常不会影响其他订阅者
- 内存泄漏:及时 unregister 不再需要的订阅者
Hashing(哈希)
Guava 提供了强大的哈希工具,包括常见的哈希算法、布隆过滤器和一致性哈希。
核心 API
| 类/接口 | 说明 |
|---|---|
HashFunction |
哈希函数接口 |
HashCode |
哈希码值 |
Hasher |
哈希计算器 |
BloomFilter |
布隆过滤器 |
Hashing |
哈希工具类 |
代码示例
1 | |
哈希算法选择
| 算法 | 特点 | 使用场景 |
|---|---|---|
md5 |
快速但已不安全 | 非安全场景的哈希 |
sha256 |
安全 | 安全哈希需求 |
murmur3_128 |
极高性能 | 缓存、数据分片 |
sipHash24 |
安全且快速 | 防止哈希碰撞攻击 |
goodFastHash |
自适应快速 | 通用快速哈希 |
使用建议
- 安全哈希:使用
sha256或sipHash24 - 高性能哈希:使用
murmur3_128或goodFastHash - 布隆过滤器:用于去重、黑名单检查等场景
- 一致性哈希:用于分布式缓存、负载均衡
Concurrency(并发工具)
Guava 提供了增强的并发工具,包括可监听的 Future、限流器等。
核心 API
| 类/接口 | 说明 |
|---|---|
ListenableFuture |
可监听的 Future |
SettableFuture |
可手动设置的 Future |
Futures |
Future 工具类 |
MoreExecutors |
Executor 工具类 |
RateLimiter |
令牌桶限流器 |
代码示例
1 | |
与 Java 8 CompletableFuture 的对比
| 特性 | Guava ListenableFuture | Java 8 CompletableFuture |
|---|---|---|
| 回调机制 | addCallback() |
thenApply(), thenAccept() |
| 组合操作 | allAsList() |
allOf(), anyOf() |
| 异常处理 | onFailure() |
exceptionally(), handle() |
| 限流器 | RateLimiter |
无内置支持 |
| 推荐使用 | Java 7 项目 | Java 8+ 项目 |
使用建议
- Java 8+ 项目:优先使用
CompletableFuture - 限流场景:使用
RateLimiter实现令牌桶算法 - 回调链:使用
Futures.transform()组合多个异步操作 - 资源管理:记得关闭 ExecutorService
IO(输入输出)
Guava IO 提供了简化的 IO 操作工具类,使文件和流处理更加便捷。
核心 API
| 工具类 | 说明 |
|---|---|
ByteStreams |
字节流工具 |
CharStreams |
字符流工具 |
Files |
文件操作工具 |
ByteSource/CharSource |
字节/字符源 |
ByteSink/CharSink |
字节/字符目标 |
Resources |
资源读取工具 |
BaseEncoding |
Base 编解码 |
代码示例
1 | |
使用建议
- 简化 IO 操作:使用
Files工具类替代复杂的 IO 代码 - 资源管理:使用
ByteSource和CharSource封装数据源 - 编码处理:始终指定 Charset,避免平台依赖
- 异常处理:IO 操作需要处理 IOException
Primitives(原始类型工具)
Guava 为 Java 原始类型提供了专门的工具类,避免自动装箱的性能开销。
核心 API
| 工具类 | 对应类型 | 主要方法 |
|---|---|---|
Ints |
int | asList, toArray, contains, max, min, join |
Longs |
long | asList, toArray, contains, max, min, join |
Doubles |
double | asList, toArray, contains, max, min, join |
Floats |
float | asList, toArray, contains, max, min, join |
Shorts |
short | asList, toArray, contains, max, min, join |
Bytes |
byte | asList, toArray, contains, max, min, join |
Chars |
char | asList, toArray, contains, max, min, join |
Booleans |
boolean | asList, toArray, contains, countTrue |
代码示例
1 | |
与自动装箱的性能对比
| 操作 | 原始类型数组 | 包装类型 List | 性能差异 |
|---|---|---|---|
| 存储 | 直接存储 | 对象包装 | 数倍差异 |
| 计算 | 直接计算 | 拆箱计算 | 数倍差异 |
| 内存 | 连续内存 | 对象引用 | 数倍差异 |
| 缓存 | 缓存友好 | 缓存不友好 | 显著差异 |
使用建议
- 优先使用原始类型:在性能敏感的场景使用原始类型数组
- 避免频繁装箱:使用
Ints等工具类减少装箱拆箱 - 大数据量:对于大数据量,原始类型数组性能优势明显
- API 简化:使用工具类方法简化常见操作
总结
Guava 是一个功能强大的 Java 工具库,为开发者提供了丰富的实用工具:
Collections(集合扩展)
- 不可变集合提供了线程安全和防御性编程的最佳实践
- 新集合类型(Multiset、Multimap、BiMap、Table、RangeSet、RangeMap 等)解决了特定的业务需求
- 工具类(Lists、Sets、Maps、Iterables)简化了常见操作
- 与 Java 8 Stream API 互补使用,可以发挥更大的威力
Cache(缓存)
- 高性能本地缓存,基于 ConcurrentHashMap 增强
- 支持自动加载、手动加载、过期策略、驱逐监听
- 提供
RateLimiter令牌桶限流器 - 新项目建议迁移到 Caffeine
Strings(字符串处理)
- Strings 工具类简化空值处理和字符串操作
- Joiner 和 Splitter 提供灵活的字符串连接和拆分
- CharMatcher 强大的字符匹配和处理
- CaseFormat 支持多种命名风格转换
Preconditions(前置条件检查)
- 提供简洁的前置条件验证方法
- 比 Java assert 更可靠,比手动检查更简洁
- 是防御性编程的重要工具
Optional(可选值)
- 明确表示可能为 null 的值,避免 NPE
- 提供
transform()等链式操作 - Java 8+ 项目建议使用
java.util.Optional
Ordering(排序器)
- 提供丰富的链式排序 API
- 支持复合排序、null 处理、基于函数排序
- Java 8+ 项目建议使用 Stream API 和 Comparator
EventBus(事件总线)
- 实现发布-订阅模式,组件间松耦合通信
- 支持同步和异步事件处理
- 适合轻量级项目,复杂场景建议使用 Spring Event
Hashing(哈希)
- 提供多种哈希算法(MD5、SHA256、Murmur3 等)
- BloomFilter 布隆过滤器用于高效去重
- consistentHash 一致性哈希用于分布式系统
Concurrency(并发工具)
- ListenableFuture 增强异步编程能力
- Futures 工具类简化 Future 组合操作
- RateLimiter 令牌桶限流器
- Java 8+ 项目建议使用 CompletableFuture
IO(输入输出)
- ByteStreams 和 CharStreams 简化流操作
- Files 工具类提供便捷的文件操作
- ByteSource/CharSource 和 ByteSink/CharSink 封装数据源和目标
- BaseEncoding 支持多种 Base 编解码
Primitives(原始类型工具)
- 为所有原始类型提供专门的工具类
- 避免自动装箱的性能开销
- 性能敏感场景的首选
使用建议
在实际项目中,合理使用 Guava 可以显著提高代码质量和开发效率:
-
Java 7 项目:全面使用 Guava 的各种功能
-
Java 8+ 项目:
- 集合操作:优先使用 Stream API,特殊集合类型使用 Guava
- Optional:使用
java.util.Optional - 异步编程:使用
CompletableFuture - 排序:使用 Comparator
- 缓存:使用 Caffeine
- 其他工具类:继续使用 Guava
-
性能优化:使用 Primitives 工具类避免装箱拆箱
-
防御性编程:使用 Preconditions 和 Optional
-
简化代码:使用 Strings、Joiner、Splitter 等工具类





