Google Guava 是 Google 开发的 Java 核心库,提供了集合、缓存、并发、字符串处理、I/O 等领域的增强工具。相比 Apache Commons,Guava 更现代化,设计理念更接近函数式编程风格。

概述

Guava 的设计哲学:

  • 不可变优先:大量使用不可变集合
  • 预防式设计:快速失败(fail-fast),尽早暴露问题
  • 函数式风格:Predicate、Function、Supplier 等函数式接口
  • 性能优化:经过 Google 大规模生产环境验证

版本要求:Guava 33.x 需要 Java 8+,充分利用 Stream 和 Optional。

Maven 依赖

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>33.3.1-jre</version>
</dependency>

注意:Guava 有两个版本:guava(JRE)和 guava-android。服务端开发使用 JRE 版本。

不可变集合

Guava 的核心设计理念:不可变集合优先

创建不可变集合

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableMap;

// of 方法创建
ImmutableList<String> list = ImmutableList.of("a", "b", "c");
ImmutableSet<String> set = ImmutableSet.of("a", "b", "c");
ImmutableMap<String, Integer> map = ImmutableMap.of("one", 1, "two", 2);

// Builder 模式
ImmutableList<String> list = ImmutableList.<String>builder()
    .add("a")
    .add("b", "c")
    .build();

ImmutableMap<String, Integer> map = ImmutableMap.<String, Integer>builder()
    .put("one", 1)
    .put("two", 2)
    .build();

// 从现有集合复制
ImmutableList<String> copy = ImmutableList.copyOf(existingList);

不可变集合的特点

// 不可变集合拒绝修改操作
ImmutableList<String> list = ImmutableList.of("a", "b");
list.add("c");  // 抛出 UnsupportedOperationException

// 线程安全:无需同步
// 内存高效:比可变集合占用更少内存
// 可靠性:作为返回值不会被调用方修改

不可变集合类型

可变类型不可变类型
ArrayListImmutableList
HashSetImmutableSet
LinkedHashSetImmutableSortedSet
HashMapImmutableMap
LinkedHashMapImmutableSortedMap

新集合类型

Guava 提供了 JDK 没有的集合类型。

Multiset - 可重复元素的 Set

import com.google.common.collect.HashMultiset;
import com.google.common.collect.Multiset;

Multiset<String> multiset = HashMultiset.create();
multiset.add("a");
multiset.add("a");
multiset.add("b");

multiset.count("a");     // 2
multiset.count("b");     // 1
multiset.size();          // 3(总元素数)
multiset.elementSet();    // [a, b](唯一元素)

// 遍历(包含重复)
for (String e : multiset) {
    System.out.println(e);  // a, a, b
}

// 遍历(唯一元素 + 计数)
for (Multiset.Entry<String> entry : multiset.entrySet()) {
    System.out.println(entry.getElement() + ": " + entry.getCount());
}

Multimap - 一键多值

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.SetMultimap;

// ListMultimap:允许重复值
ListMultimap<String, String> listMultimap = ArrayListMultimap.create();
listMultimap.put("key", "value1");
listMultimap.put("key", "value2");
listMultimap.put("key", "value1");  // 允许重复
listMultimap.get("key");  // [value1, value2, value1]

// SetMultimap:值不重复
SetMultimap<String, String> setMultimap = HashMultimap.create();
setMultimap.put("key", "value1");
setMultimap.put("key", "value2");
setMultimap.put("key", "value1");  // 忽略重复
setMultimap.get("key");  // [value1, value2]

// 常用操作
multimap.putAll("key", Arrays.asList("a", "b", "c"));
multimap.remove("key", "a");
multimap.removeAll("key");
multimap.containsKey("key");
multimap.containsValue("value");
multimap.containsEntry("key", "value");
multimap.size();          // 总键值对数
multimap.keySet();        // 所有 key
multimap.values();        // 所有 value
multimap.entries();       // 所有 Map.Entry
multimap.asMap();         // 转为 Map<K, Collection<V>>

BiMap - 双向映射

import com.google.common.collect.HashBiMap;
import com.google.common.collect.BiMap;

BiMap<String, Integer> biMap = HashBiMap.create();
biMap.put("one", 1);
biMap.put("two", 2);

// 正向查找
biMap.get("one");         // 1

// 反向查找
biMap.inverse().get(1);   // "one"

// 值必须唯一
biMap.put("three", 1);    // 抛出 IllegalArgumentException

// 强制覆盖
biMap.forcePut("three", 1);  // 覆盖 "one" -> 1
biMap.get("one");         // null
biMap.get("three");       // 1

Table - 二维表结构

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;

Table<String, String, Integer> table = HashBasedTable.create();

// 行、列、值
table.put("row1", "col1", 1);
table.put("row1", "col2", 2);
table.put("row2", "col1", 3);

// 获取值
table.get("row1", "col1");  // 1

// 获取行
Map<String, Integer> row1 = table.row("row1");  // {col1=1, col2=2}

// 获取列
Map<String, Integer> col1 = table.column("col1");  // {row1=1, row2=3}

// 遍历
for (Table.Cell<String, String, Integer> cell : table.cellSet()) {
    System.out.println(cell.getRowKey() + ", " + cell.getColumnKey() + " = " + cell.getValue());
}

// 其他操作
table.rowKeySet();       // 所有行键
table.columnKeySet();    // 所有列键
table.rowMap();          // Map<行键, Map<列键, 值>>
table.columnMap();       // Map<列键, Map<行键, 值>>

RangeSet - 范围集合

import com.google.common.collect.ImmutableRangeSet;
import com.google.common.collect.Range;
import com.google.common.collect.RangeSet;
import com.google.common.collect.TreeRangeSet;

RangeSet<Integer> rangeSet = TreeRangeSet.create();

// 添加范围
rangeSet.add(Range.closed(1, 10));    // [1, 10]
rangeSet.add(Range.closedOpen(11, 15)); // [11, 15)
rangeSet.add(Range.open(15, 20));       // (15, 20)

// 查询
rangeSet.contains(5);      // true
rangeSet.contains(15);     // false(15 在 [11,15) 和 (15,20) 的间隙)
rangeSet.rangeContaining(5);  // [1, 10]

// 范围操作
rangeSet.encloses(Range.closed(2, 5));  // 是否完全包含
rangeSet.intersects(Range.closed(5, 15));  // 是否相交

// 补集
RangeSet<Integer> complement = rangeSet.complement();

RangeMap - 范围映射

import com.google.common.collect.Range;
import com.google.common.collect.RangeMap;
import com.google.common.collect.TreeRangeMap;

RangeMap<Integer, String> rangeMap = TreeRangeMap.create();

rangeMap.put(Range.closed(1, 10), "low");
rangeMap.put(Range.closed(11, 20), "medium");
rangeMap.put(Range.closed(21, 30), "high");

// 查询
rangeMap.get(5);    // "low"
rangeMap.get(15);   // "medium"
rangeMap.get(100);  // null

// 获取条目
Map.Entry<Range<Integer>, String> entry = rangeMap.getEntry(5);

集合工具类

Lists / Sets / Maps

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.collect.Maps;

// 创建
List<String> list = Lists.newArrayList("a", "b", "c");
Set<String> set = Sets.newHashSet("a", "b", "c");
Map<String, Integer> map = Maps.newHashMap();

// 分区
List<String> bigList = Lists.newArrayList(/* 100 elements */);
List<List<String>> partitions = Lists.partition(bigList, 10);  // 每组 10 个

// 反转
List<String> reversed = Lists.reverse(list);  // [c, b, a]

// 笛卡尔积
Set<List<String>> cartesian = Sets.cartesianProduct(
    ImmutableSet.of("a", "b"),
    ImmutableSet.of("1", "2")
);  // [[a,1], [a,2], [b,1], [b,2]]

// 集合运算
Set<String> set1 = Sets.newHashSet("a", "b", "c");
Set<String> set2 = Sets.newHashSet("b", "c", "d");

Sets.union(set1, set2);          // [a, b, c, d]
Sets.intersection(set1, set2);  // [b, c]
Sets.difference(set1, set2);     // [a]
Sets.symmetricDifference(set1, set2);  // [a, d]

// 过滤
Sets.filter(set, e -> e.startsWith("a"));

// Map 差异
Map<String, Integer> map1 = ImmutableMap.of("a", 1, "b", 2);
Map<String, Integer> map2 = ImmutableMap.of("b", 2, "c", 3);
MapDifference<String, Integer> diff = Maps.difference(map1, map2);

diff.entriesOnlyOnLeft();    // {a=1}
diff.entriesOnlyOnRight();   // {c=3}
diff.entriesInCommon();      // {b=2}
diff.entriesDiffering();     // 值不同的条目

Ordering - 链式比较器

import com.google.common.collect.Ordering;

Ordering<String> ordering = Ordering.natural().reverse();  // 自然序反转

List<String> list = Lists.newArrayList("c", "a", "b");

// 排序
ordering.sortedCopy(list);  // [c, b, a]

// 查找
ordering.min(list);   // "a"
ordering.max(list);   // "c"

// 判断
ordering.isOrdered(list);       // false
ordering.isStrictlyOrdered(list);  // false

// 复合排序
Ordering<Person> byAge = Ordering.natural().onResultOf(Person::getAge);
Ordering<Person> byName = Ordering.natural().onResultOf(Person::getName);
Ordering<Person> compound = byAge.compound(byName);

// 空值处理
Ordering.natural().nullsFirst();   // null 排最前
Ordering.natural().nullsLast();    // null 排最后

// 取前 N 个
ordering.greatestOf(list, 2);  // [c, b]
ordering.leastOf(list, 2);     // [a, b]

字符串处理

Joiner - 字符串拼接

import com.google.common.base.Joiner;

// 基本用法
Joiner.on(",").join(Arrays.asList("a", "b", "c"));  // "a,b,c"

// 跳过 null
Joiner.on(",").skipNulls().join(Arrays.asList("a", null, "c"));  // "a,c"

// 替换 null
Joiner.on(",").useForNull("N/A").join(Arrays.asList("a", null, "c"));  // "a,N/A,c"

// 拼接 Map
Joiner.on(",").withKeyValueSeparator("=").join(ImmutableMap.of("a", 1, "b", 2));  // "a=1,b=2"

// 追加到 Appendable
Joiner.on(",").appendTo(stringBuilder, list);

Splitter - 字符串分割

import com.google.common.base.Splitter;

// 基本用法
Splitter.on(",").split("a,b,c");  // [a, b, c]

// 正则分割
Splitter.onPattern("\\s+").split("a  b   c");

// 固定长度
Splitter.fixedLength(3).split("abcdef");  // [abc, def]

// 去除空白
Splitter.on(",").trimResults().split("a , b , c");  // [a, b, c]

// 过滤空字符串
Splitter.on(",").omitEmptyStrings().split("a,,b,c");  // [a, b, c]

// 限制分割数量
Splitter.on(",").limit(2).split("a,b,c");  // [a, b,c]

// 分割为 Map
Splitter.on(",").withKeyValueSeparator("=").split("a=1,b=2");  // {a=1, b=2}

// 转为 List
List<String> list = Splitter.on(",").splitToList("a,b,c");

Strings - 字符串工具

import com.google.common.base.Strings;

// 空值处理
Strings.nullToEmpty(null);   // ""
Strings.emptyToNull("");     // null
Strings.isNullOrEmpty("");   // true

// 填充
Strings.padStart("7", 3, '0');   // "007"
Strings.padEnd("7", 3, '0');     // "700"

// 重复
Strings.repeat("ab", 3);  // "ababab"

// 公共前缀/后缀
Strings.commonPrefix("foobar", "foobaz");  // "fooba"
Strings.commonSuffix("foobar", "bazbar");  // "bar"

CaseFormat - 命名格式转换

import com.google.common.base.CaseFormat;

CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, "helloWorld");     // "HelloWorld"
CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, "helloWorld"); // "hello_world"
CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, "helloWorld"); // "HELLO_WORLD"
CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, "HELLO_WORLD"); // "helloWorld"

函数式编程

Guava 在 Java 8 之前就提供了函数式接口,现在可以与 Stream API 配合使用。

Predicate - 断言

import com.google.common.base.Predicate;
import com.google.common.base.Predicates;

// 基本用法
Predicate<String> isEmpty = String::isEmpty;
Predicate<String> isLong = s -> s.length() > 5;

// 组合
Predicate<String> combined = Predicates.and(isEmpty, isLong);
Predicate<String> either = Predicates.or(isEmpty, isLong);
Predicate<String> negated = Predicates.not(isEmpty);

// 集合过滤(传统方式)
Iterable<String> filtered = Iterables.filter(list, isLong);

// 与 Stream 配合
List<String> result = list.stream()
    .filter(isLong)
    .collect(Collectors.toList());

Function - 转换

import com.google.common.base.Function;
import com.google.common.base.Functions;

// 基本用法
Function<String, Integer> length = String::length;
Function<String, String> upper = String::toUpperCase;

// 组合
Function<String, Integer> composed = Functions.compose(String::length, String::trim);

// 集合转换(传统方式)
List<Integer> lengths = Lists.transform(list, String::length);

// 与 Stream 配合
List<Integer> result = list.stream()
    .map(String::length)
    .collect(Collectors.toList());

Supplier - 延迟计算

import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;

Supplier<ExpensiveObject> supplier = ExpensiveObject::new;

// 延迟获取
ExpensiveObject obj = supplier.get();

// 记忆化(缓存结果)
Supplier<ExpensiveObject> memoized = Suppliers.memoize(supplier);
memoized.get();  // 第一次调用时创建
memoized.get();  // 后续调用返回缓存

// 带过期时间的记忆化
Supplier<ExpensiveObject> memoizedWithTimeout = 
    Suppliers.memoizeWithExpiration(supplier, 10, TimeUnit.MINUTES);

Optional - 可选值

注意:Java 8+ 推荐使用 java.util.Optional,但 Guava 的 Optional 仍在一些老代码中使用。

import com.google.common.base.Optional;

// 创建
Optional<String> present = Optional.of("value");
Optional<String> absent = Optional.absent();
Optional<String> nullable = Optional.fromNullable(maybeNull);

// 检查
present.isPresent();  // true
absent.isPresent();   // false

// 获取
present.get();                    // "value"
present.or("default");            // "value"
absent.or("default");             // "default"
present.or(Supplier);             // 延迟默认值

// 转换
Optional<Integer> length = present.transform(String::length);

// 与 Java Optional 互转
java.util.Optional<String> javaOptional = present.toJavaUtil();
Optional<String> guavaOptional = Optional.fromJavaUtil(javaOptional);

缓存

Guava Cache 是高性能的本地缓存实现。

基本使用

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import java.util.concurrent.TimeUnit;

Cache<String, User> cache = CacheBuilder.newBuilder()
    .maximumSize(1000)                          // 最大条目数
    .expireAfterWrite(10, TimeUnit.MINUTES)     // 写入后过期
    .expireAfterAccess(5, TimeUnit.MINUTES)     // 访问后过期
    .build();

// 手动放入
cache.put("key", user);

// 获取
User user = cache.getIfPresent("key");

// 获取所有
Map<String, User> all = cache.getAllPresent(keys);

// 失效
cache.invalidate("key");
cache.invalidateAll();

LoadingCache - 自动加载

import com.google.common.cache.LoadingCache;
import com.google.common.cache.CacheLoader;

LoadingCache<String, User> cache = CacheBuilder.newBuilder()
    .maximumSize(1000)
    .expireAfterWrite(10, TimeUnit.MINUTES)
    .build(new CacheLoader<String, User>() {
        @Override
        public User load(String key) {
            return loadFromDatabase(key);  // 缓存未命中时加载
        }
    });

// 获取(自动加载)
User user = cache.get("key");  // 如果不存在,调用 CacheLoader.load()

// 批量获取
Map<String, User> users = cache.getAll(Arrays.asList("key1", "key2"));

// 刷新(异步)
cache.refresh("key");

缓存统计

Cache<String, User> cache = CacheBuilder.newBuilder()
    .maximumSize(1000)
    .recordStats()  // 启用统计
    .build();

CacheStats stats = cache.stats();
stats.hitCount();       // 命中次数
stats.missCount();      // 未命中次数
stats.hitRate();        // 命中率
stats.evictionCount();  // 驱逐次数
stats.loadCount();      // 加载次数
stats.averageLoadPenalty();  // 平均加载时间(纳秒)

移除监听器

Cache<String, User> cache = CacheBuilder.newBuilder()
    .maximumSize(1000)
    .removalListener(notification -> {
        System.out.println("Removed: " + notification.getKey() + 
                          ", cause: " + notification.getCause());
    })
    .build();

// RemovalCause: EXPLICIT(显式删除)、REPLACED(被替换)、SIZE(容量限制)、EXPIRED(过期)

高级配置

LoadingCache<String, User> cache = CacheBuilder.newBuilder()
    // 容量限制
    .maximumSize(1000)                    // 最大条目数
    .maximumWeight(10000)                // 最大权重
    .weigher((key, value) -> value.size())  // 权重计算
    
    // 过期策略
    .expireAfterWrite(10, TimeUnit.MINUTES)   // 写入后过期
    .expireAfterAccess(5, TimeUnit.MINUTES)   // 访问后过期
    .expireAfter(Expiry.creating(...))        // 自定义过期策略
    
    // 刷新策略
    .refreshAfterWrite(5, TimeUnit.MINUTES)   // 写入后刷新
    
    // 弱引用
    .weakKeys()                           // 弱引用键
    .weakValues()                         // 弱引用值
    .softValues()                         // 软引用值
    
    // 其他
    .recordStats()                        // 记录统计
    .removalListener(listener)            // 移除监听
    .build(loader);

并发工具

ListenableFuture - 可监听的 Future

注意:Java 8+ 推荐使用 CompletableFuture,但 Guava 的 ListenableFuture 在某些场景仍有用。

import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.AsyncFunction;

ListeningExecutorService executor = MoreExecutors.listeningDecorator(
    Executors.newFixedThreadPool(10)
);

// 提交任务
ListenableFuture<String> future = executor.submit(() -> "result");

// 添加回调
Futures.addCallback(future, new FutureCallback<String>() {
    @Override
    public void onSuccess(String result) {
        System.out.println("Success: " + result);
    }
    
    @Override
    public void onFailure(Throwable t) {
        System.out.println("Failed: " + t.getMessage());
    }
}, executor);

// 转换
ListenableFuture<Integer> transformed = Futures.transform(future, String::length, executor);

// 异步链式调用
ListenableFuture<User> userFuture = executor.submit(() -> getUser(id));
ListenableFuture<List<Order>> ordersFuture = Futures.transformAsync(userFuture, 
    user -> executor.submit(() -> getOrders(user)), executor);

// 组合多个 Future
ListenableFuture<String> f1 = executor.submit(() -> "a");
ListenableFuture<String> f2 = executor.submit(() -> "b");
ListenableFuture<List<String>> all = Futures.allAsList(f1, f2);
ListenableFuture<Object> any = Futures.anyOf(f1, f2);

RateLimiter - 限流器

import com.google.common.util.concurrent.RateLimiter;

// 每秒 10 个请求
RateLimiter limiter = RateLimiter.create(10.0);

// 阻塞获取许可
limiter.acquire();  // 返回等待时间(秒)
doSomething();

// 尝试获取(非阻塞)
if (limiter.tryAcquire()) {
    doSomething();
} else {
    handleRejection();
}

// 批量获取
limiter.acquire(5);  // 获取 5 个许可

// 预热模式(逐渐增加速率)
RateLimiter warmup = RateLimiter.create(10.0, 5, TimeUnit.SECONDS);

MoreExecutors - 执行器工具

import com.google.common.util.concurrent.MoreExecutors;

// 直接执行器(当前线程执行)
Executor directExecutor = MoreExecutors.directExecutor();

// 退出时关闭
ExecutorService executor = MoreExecutors.getExitingExecutorService(
    (ThreadPoolExecutor) Executors.newFixedThreadPool(10),
    5, TimeUnit.MINUTES
);

// 装饰为 ListenableFuture 支持
ListeningExecutorService listening = MoreExecutors.listeningDecorator(executor);

I/O 工具

ByteStreams / CharStreams

import com.google.common.io.ByteStreams;
import com.google.common.io.CharStreams;
import java.io.*;

// 流转字节数组
byte[] bytes = ByteStreams.toByteArray(inputStream);

// 流转字符串
String text = CharStreams.toString(new InputStreamReader(inputStream, StandardCharsets.UTF_8));

// 复制流
long copied = ByteStreams.copy(inputStream, outputStream);

// 跳过字节
ByteStreams.skipFully(inputStream, 100);

// 读取指定长度
byte[] buffer = new byte[1024];
ByteStreams.read(inputStream, buffer, 0, 1024);

Files

import com.google.common.io.Files;
import java.io.File;
import java.nio.charset.StandardCharsets;

File file = new File("test.txt");

// 读取
String content = Files.asCharSource(file, StandardCharsets.UTF_8).read();
List<String> lines = Files.readLines(file, StandardCharsets.UTF_8);
byte[] bytes = Files.toByteArray(file);

// 写入
Files.asCharSink(file, StandardCharsets.UTF_8).write("content");
Files.asCharSink(file, StandardCharsets.UTF_8).writeLines(Arrays.asList("line1", "line2"));
Files.write(bytes, file);

// 追加
Files.asCharSink(file, StandardCharsets.UTF_8, FileWriteMode.APPEND).write("more");

// 复制
Files.copy(source, dest);
Files.move(source, dest);

// 文件属性
Files.getFileExtension("test.txt");     // "txt"
Files.getNameWithoutExtension("test.txt");  // "test"
Files.isFile(file);
Files.isDirectory(file);

// 创建临时文件
File temp = Files.createTempDir();

// 计算哈希
HashCode hash = Files.asByteSource(file).hash(Hashing.sha256());

ByteSource / CharSource

import com.google.common.io.ByteSource;
import com.google.common.io.CharSource;
import com.google.common.io.FileWriteMode;

// 创建源
ByteSource byteSource = Files.asByteSource(file);
CharSource charSource = Files.asCharSource(file, StandardCharsets.UTF_8);

// 读取
byte[] bytes = byteSource.read();
String text = charSource.read();
List<String> lines = charSource.readLines();

// 流式处理
try (InputStream is = byteSource.openStream()) {
    // 处理流
}

// 切片
ByteSource slice = byteSource.slice(0, 1024);

// 组合
ByteSource combined = ByteSource.concat(source1, source2);

// 空/零
ByteSource empty = ByteSource.empty();
CharSource emptyChar = CharSource.empty();

哈希工具

Hashing

import com.google.common.hash.Hashing;
import com.google.common.hash.HashCode;
import com.google.common.hash.HashFunction;
import com.google.common.hash.Funnel;
import com.google.common.hash.PrimitiveSink;

// 字符串哈希
HashCode md5 = Hashing.md5().hashString("hello", StandardCharsets.UTF_8);
HashCode sha256 = Hashing.sha256().hashString("hello", StandardCharsets.UTF_8);
HashCode sha512 = Hashing.sha512().hashString("hello", StandardCharsets.UTF_8);

// 字节数组哈希
HashCode hash = Hashing.sha256().hashBytes(bytes);

// 文件哈希
HashCode fileHash = Files.asByteSource(file).hash(Hashing.sha256());

// 获取结果
String hex = hash.toString();  // 十六进制字符串
byte[] bytes = hash.asBytes();  // 字节数组
int intValue = hash.asInt();    // int 值
long longValue = hash.asLong(); // long 值

// 一致性哈希
int bucket = Hashing.consistentHash(hash, 10);  // 映射到 0-9 桶

// 布隆过滤器
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;

BloomFilter<String> filter = BloomFilter.create(
    Funnels.stringFunnel(StandardCharsets.UTF_8),
    10000,  // 预期元素数
    0.01    // 误判率
);

filter.put("element");
boolean mightContain = filter.mightContain("element");  // true
boolean mightContainOther = filter.mightContain("other");  // false(或误判为 true)

前置条件检查

Guava 提供了优雅的前置条件检查方法。

import com.google.common.base.Preconditions;

// 非空检查
Preconditions.checkNotNull(value);                    // 为 null 抛 NPE
Preconditions.checkNotNull(value, "value 不能为空");  // 自定义消息
Preconditions.checkNotNull(value, "%s 不能为空", "value");  // 格式化消息

// 条件检查
Preconditions.checkArgument(age >= 0, "年龄必须非负");
Preconditions.checkArgument(age >= 0 && age <= 150, "年龄必须在 0-150 之间");

// 状态检查
Preconditions.checkState(isInitialized, "未初始化");
Preconditions.checkState(count > 0, "计数必须大于 0");

// 索引检查
Preconditions.checkElementIndex(index, size, "index");
Preconditions.checkPositionIndex(index, size, "index");
Preconditions.checkPositionIndexes(start, end, size);

事件总线

Guava EventBus 是轻量级的发布-订阅模式实现。

同步事件总线

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;

EventBus eventBus = new EventBus();

// 定义订阅者
class OrderEventHandler {
    @Subscribe
    public void handleOrderCreated(OrderCreatedEvent event) {
        System.out.println("Order created: " + event.getOrderId());
    }
    
    @Subscribe
    public void handleOrderCancelled(OrderCancelledEvent event) {
        System.out.println("Order cancelled: " + event.getOrderId());
    }
}

// 注册订阅者
eventBus.register(new OrderEventHandler());

// 发布事件
eventBus.post(new OrderCreatedEvent("order-123"));
eventBus.post(new OrderCancelledEvent("order-123"));

异步事件总线

import com.google.common.eventbus.AsyncEventBus;
import java.util.concurrent.Executors;

AsyncEventBus asyncEventBus = new AsyncEventBus(
    Executors.newCachedThreadPool()
);

// 使用方式与同步相同
asyncEventBus.register(handler);
asyncEventBus.post(event);

Dead Event 处理

import com.google.common.eventbus.DeadEvent;

class DeadEventHandler {
    @Subscribe
    public void handleDeadEvent(DeadEvent event) {
        System.out.println("No subscriber for: " + event.getEvent());
    }
}

eventBus.register(new DeadEventHandler());

停止器

Stopwatch 用于计时。

import com.google.common.base.Stopwatch;
import java.util.concurrent.TimeUnit;

Stopwatch stopwatch = Stopwatch.createStarted();

// 执行操作
doSomething();

stopwatch.elapsed(TimeUnit.MILLISECONDS);  // 已过毫秒数
stopwatch.elapsed(TimeUnit.SECONDS);        // 已过秒数

stopwatch.stop();  // 停止
stopwatch.reset();  // 重置
stopwatch.start();  // 重新开始

// 创建未启动的计时器
Stopwatch stopwatch = Stopwatch.createUnstarted();

最佳实践

1. 与 Java 8+ 配合

// 优先使用 Java 8 Optional
Optional<String> javaOptional = Optional.of("value");

// 优先使用 Stream API
List<String> filtered = list.stream()
    .filter(StringUtils::isNotBlank)
    .map(String::trim)
    .collect(Collectors.toList());

// Guava 集合工具作为补充
List<List<String>> partitions = Lists.partition(bigList, 100);

2. 不可变集合优先

// 返回值使用不可变集合
public List<String> getNames() {
    return ImmutableList.copyOf(names);
}

// 参数接受不可变集合
public void process(ImmutableList<String> names) {
    // 保证不会被修改
}

3. 前置条件检查

public void process(String name, int age) {
    this.name = Preconditions.checkNotNull(name, "name 不能为空");
    Preconditions.checkArgument(age >= 0, "age 必须非负: %s", age);
    Preconditions.checkState(isInitialized, "服务未初始化");
}

4. 缓存使用场景

// 适合:读多写少、计算昂贵、可接受短暂不一致
LoadingCache<String, User> userCache = CacheBuilder.newBuilder()
    .maximumSize(10000)
    .expireAfterWrite(10, TimeUnit.MINUTES)
    .build(key -> loadUserFromDatabase(key));

// 不适合:需要强一致性、数据量极大、持久化需求

Guava vs Apache Commons

功能GuavaApache Commons
字符串Joiner/SplitterStringUtils
集合不可变集合、新类型CollectionUtils
I/OByteSource/CharSourceIOUtils/FileUtils
缓存Cache
并发ListenableFuture/RateLimiter
哈希Hashing/BloomFilterCodec(仅编码)
事件EventBus

选择建议

  • 新项目优先 Guava(更现代、功能更全)
  • 老项目维护可继续使用 Commons
  • 可以混用,各取所长

参考