Guava 常用工具包完全指南

简介

Guava 是 Google 开源的 Java 核心库,提供了丰富的工具类和集合框架,能够极大提升开发效率。本文将介绍 Guava 中最常用的工具包及其实际应用。

1. 集合工具 (Collections)

1.1 不可变集合

不可变集合线程安全且不可修改,适合作为常量使用。

java 复制代码
// 创建不可变 List
ImmutableList<String> list = ImmutableList.of("A", "B", "C");

// 创建不可变 Set
ImmutableSet<Integer> set = ImmutableSet.of(1, 2, 3, 4, 5);

// 创建不可变 Map
ImmutableMap<String, Integer> map = ImmutableMap.of(
    "Java", 1,
    "Python", 2,
    "Go", 3
);

// 使用 Builder 构建复杂集合
ImmutableList<String> complexList = ImmutableList.<String>builder()
    .add("A")
    .add("B", "C")
    .addAll(Arrays.asList("D", "E"))
    .build();

1.2 Multiset - 计数集合

Multiset 允许元素重复,并可以统计元素出现次数。

java 复制代码
Multiset<String> multiset = HashMultiset.create();
multiset.add("apple");
multiset.add("apple");
multiset.add("banana");
multiset.add("apple");

System.out.println(multiset.count("apple"));  // 输出: 3
System.out.println(multiset.size());          // 输出: 4

// 遍历不重复元素
for (String element : multiset.elementSet()) {
    System.out.println(element + ": " + multiset.count(element));
}

1.3 Multimap - 一键多值映射

Multimap 允许一个键对应多个值。

java 复制代码
Multimap<String, String> multimap = ArrayListMultimap.create();
multimap.put("Fruit", "Apple");
multimap.put("Fruit", "Banana");
multimap.put("Vegetable", "Carrot");

System.out.println(multimap.get("Fruit"));  // 输出: [Apple, Banana]

// 转换为普通 Map
Map<String, Collection<String>> map = multimap.asMap();

1.4 BiMap - 双向映射

BiMap 提供键值互查的双向映射。

java 复制代码
BiMap<String, Integer> biMap = HashBiMap.create();
biMap.put("Alice", 1);
biMap.put("Bob", 2);

// 正向查询
System.out.println(biMap.get("Alice"));  // 输出: 1

// 反向查询
System.out.println(biMap.inverse().get(1));  // 输出: Alice

1.5 Table - 双键映射

Table 提供行列式的双键映射结构。

java 复制代码
Table<String, String, Integer> table = HashBasedTable.create();
table.put("2023", "Q1", 100);
table.put("2023", "Q2", 150);
table.put("2024", "Q1", 120);

// 获取值
Integer value = table.get("2023", "Q1");  // 100

// 获取某一行的所有数据
Map<String, Integer> row = table.row("2023");  // {Q1=100, Q2=150}

// 获取某一列的所有数据
Map<String, Integer> column = table.column("Q1");  // {2023=100, 2024=120}

2. 字符串工具 (Strings)

2.1 Joiner - 连接器

java 复制代码
// 基本连接
String result = Joiner.on(", ").join(Arrays.asList("A", "B", "C"));
// 输出: A, B, C

// 跳过 null 值
String withoutNull = Joiner.on(", ")
    .skipNulls()
    .join("A", null, "B", "C");
// 输出: A, B, C

// 替换 null 值
String replaceNull = Joiner.on(", ")
    .useForNull("N/A")
    .join("A", null, "B");
// 输出: A, N/A, B

// Map 连接
Map<String, String> map = ImmutableMap.of("name", "John", "age", "30");
String mapStr = Joiner.on("&").withKeyValueSeparator("=").join(map);
// 输出: name=John&age=30

2.2 Splitter - 分割器

java 复制代码
// 基本分割
Iterable<String> parts = Splitter.on(',').split("A,B,C");

// 去除空白字符
Iterable<String> trimmed = Splitter.on(',')
    .trimResults()
    .split(" A , B , C ");

// 忽略空字符串
Iterable<String> noEmpty = Splitter.on(',')
    .omitEmptyStrings()
    .split("A,,B,C");

// 限制分割数量
Iterable<String> limited = Splitter.on(',')
    .limit(2)
    .split("A,B,C,D");
// 结果: [A, B,C,D]

// 分割 Map
Map<String, String> kvMap = Splitter.on('&')
    .withKeyValueSeparator('=')
    .split("name=John&age=30");

2.3 Strings 工具类

java 复制代码
// null 转空字符串
String str = Strings.nullToEmpty(null);  // ""

// 空字符串转 null
String nullStr = Strings.emptyToNull("");  // null

// 字符串填充
String padded = Strings.padStart("7", 3, '0');  // "007"
String paddedEnd = Strings.padEnd("7", 3, '0'); // "700"

// 重复字符串
String repeated = Strings.repeat("ab", 3);  // "ababab"

// 公共前缀
String prefix = Strings.commonPrefix("testing", "test");  // "test"

// 公共后缀
String suffix = Strings.commonSuffix("testing", "interesting");  // "ting"

3. 缓存工具 (Cache)

Guava Cache 提供本地缓存功能,支持多种过期策略。

java 复制代码
LoadingCache<String, String> cache = CacheBuilder.newBuilder()
    .maximumSize(1000)                          // 最大容量
    .expireAfterWrite(10, TimeUnit.MINUTES)    // 写入后过期
    .expireAfterAccess(5, TimeUnit.MINUTES)    // 访问后过期
    .recordStats()                              // 启用统计
    .build(new CacheLoader<String, String>() {
        @Override
        public String load(String key) throws Exception {
            return loadFromDatabase(key);  // 缓存加载逻辑
        }
    });

// 使用缓存
try {
    String value = cache.get("key");
} catch (ExecutionException e) {
    e.printStackTrace();
}

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

// 失效缓存
cache.invalidate("key");

// 查看统计
CacheStats stats = cache.stats();
System.out.println("命中率: " + stats.hitRate());

4. 集合工具类 (Lists, Sets, Maps)

4.1 Lists 工具

java 复制代码
// 创建 ArrayList
List<String> list = Lists.newArrayList("A", "B", "C");

// 指定容量
List<String> capacityList = Lists.newArrayListWithCapacity(100);

// 反转列表
List<String> reversed = Lists.reverse(list);

// 分区
List<List<String>> partitions = Lists.partition(list, 2);
// 结果: [[A, B], [C]]

// 笛卡尔积
List<List<String>> cartesian = Lists.cartesianProduct(
    Lists.newArrayList("A", "B"),
    Lists.newArrayList("1", "2")
);
// 结果: [[A, 1], [A, 2], [B, 1], [B, 2]]

4.2 Sets 工具

java 复制代码
// 创建 HashSet
Set<String> set1 = Sets.newHashSet("A", "B", "C");
Set<String> set2 = Sets.newHashSet("B", "C", "D");

// 并集
Set<String> union = Sets.union(set1, set2);  // [A, B, C, D]

// 交集
Set<String> intersection = Sets.intersection(set1, set2);  // [B, C]

// 差集
Set<String> difference = Sets.difference(set1, set2);  // [A]

// 对称差集
Set<String> symmetricDifference = Sets.symmetricDifference(set1, set2);  // [A, D]

// 幂集
Set<Set<String>> powerSet = Sets.powerSet(Sets.newHashSet("A", "B"));
// 结果: [[], [A], [B], [A, B]]

4.3 Maps 工具

java 复制代码
// 创建 HashMap
Map<String, Integer> map = Maps.newHashMap();

// 从 Set 创建 Map
Set<String> keys = Sets.newHashSet("A", "B", "C");
Map<String, String> mapFromKeys = Maps.asMap(keys, key -> key.toLowerCase());

// 过滤 Map
Map<String, Integer> filtered = Maps.filterKeys(map, key -> key.startsWith("A"));

// 转换 Map 值
Map<String, String> transformed = Maps.transformValues(map, value -> "Value: " + value);

// 差异比较
MapDifference<String, Integer> diff = Maps.difference(map1, map2);
System.out.println("仅在左侧: " + diff.entriesOnlyOnLeft());
System.out.println("仅在右侧: " + diff.entriesOnlyOnRight());
System.out.println("值不同: " + diff.entriesDiffering());

5. Optional - 避免空指针

java 复制代码
// 创建 Optional
Optional<String> optional = Optional.of("Hello");
Optional<String> nullable = Optional.fromNullable(null);
Optional<String> absent = Optional.absent();

// 判断是否存在
if (optional.isPresent()) {
    System.out.println(optional.get());
}

// 提供默认值
String value = nullable.or("Default");

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

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

6. Preconditions - 前置条件检查

java 复制代码
public void processUser(String name, int age, List<String> roles) {
    // 检查非 null
    Preconditions.checkNotNull(name, "姓名不能为空");
    
    // 检查参数条件
    Preconditions.checkArgument(age >= 0 && age <= 150, 
        "年龄必须在 0-150 之间,实际值: %s", age);
    
    // 检查状态
    Preconditions.checkState(isInitialized, "服务未初始化");
    
    // 检查索引
    Preconditions.checkElementIndex(0, roles.size(), "角色列表");
    
    // 检查位置索引
    Preconditions.checkPositionIndex(1, roles.size(), "角色列表");
}

7. Objects 工具

java 复制代码
// 空值判断
boolean isNull = Objects.equal(null, null);  // true

// 哈希码
int hash = Objects.hashCode(obj1, obj2, obj3);

// toString 辅助
String str = MoreObjects.toStringHelper(this)
    .add("name", name)
    .add("age", age)
    .toString();
// 输出: ClassName{name=John, age=30}

// 比较链
int result = ComparisonChain.start()
    .compare(this.name, other.name)
    .compare(this.age, other.age)
    .result();

8. IO 工具

java 复制代码
// 读取文件
String content = Files.asCharSource(new File("test.txt"), Charsets.UTF_8).read();

// 写入文件
Files.asCharSink(new File("output.txt"), Charsets.UTF_8).write("Hello World");

// 复制文件
Files.copy(sourceFile, targetFile);

// 移动文件
Files.move(sourceFile, targetFile);

// 读取所有行
List<String> lines = Files.readLines(new File("test.txt"), Charsets.UTF_8);

// 关闭流
Closer closer = Closer.create();
try {
    InputStream in = closer.register(new FileInputStream("file.txt"));
    // 使用流
} catch (Throwable e) {
    throw closer.rethrow(e);
} finally {
    closer.close();
}

9. 数学工具 (Math)

java 复制代码
// 整数运算
int gcd = IntMath.gcd(12, 18);  // 最大公约数: 6
int mod = IntMath.mod(-5, 3);   // 模运算: 1
int pow = IntMath.pow(2, 10);   // 幂运算: 1024

// 判断是否为质数
boolean isPrime = IntMath.isPrime(17);  // true

// 阶乘
int factorial = IntMath.factorial(5);  // 120

// 二项式系数
int binomial = IntMath.binomial(5, 2);  // 10

// 浮点数比较
boolean fuzzyEquals = DoubleMath.fuzzyEquals(1.0, 1.0000001, 0.00001);

10. RateLimiter - 限流器

java 复制代码
// 创建限流器:每秒 5 个许可
RateLimiter limiter = RateLimiter.create(5.0);

// 获取许可(阻塞)
limiter.acquire();
processRequest();

// 获取多个许可
limiter.acquire(3);

// 尝试获取许可(非阻塞)
if (limiter.tryAcquire()) {
    processRequest();
} else {
    rejectRequest();
}

// 带超时的获取
if (limiter.tryAcquire(1, TimeUnit.SECONDS)) {
    processRequest();
}

Maven 依赖

xml 复制代码
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>32.1.3-jre</version>
</dependency>

总结

Guava 提供了丰富的工具类,涵盖集合、字符串、缓存、IO 等多个方面,能够显著提升 Java 开发效率。建议在项目中合理使用这些工具,减少重复造轮子,提高代码质量和可维护性。

关键优势:

  • 线程安全的不可变集合
  • 强大的集合扩展(Multimap、Table、BiMap)
  • 简洁的字符串处理
  • 高性能本地缓存
  • 完善的前置条件检查
  • 实用的限流和数学工具

通过掌握这些常用工具包,你可以写出更加简洁、高效、健壮的 Java 代码。

相关推荐
BingoGo15 分钟前
PHP 8.5 在性能、调试和运维方面的新特性
后端·php
WindrunnerMax17 分钟前
基于 NodeJs 的分布式任务队列与容器优雅停机
javascript·后端·node.js
雨中飘荡的记忆17 分钟前
Spring动态代理详解
java·spring
JienDa19 分钟前
PHP漏洞全解:从“世界上最好的语言”到“黑客的提款机”,你的代码真的安全吗?
后端
若水不如远方30 分钟前
深入理解Reactor:从单线程到主从模式演进之路
java·架构
随风飘的云30 分钟前
spring的单例对象是否线程安全
后端
掂掂三生有幸32 分钟前
多系统 + 可视化实操:openGauss 从部署到业务落地的真实体验
后端
爱分享的鱼鱼32 分钟前
Java高级查询、分页、排序
java
我很忙6538 分钟前
wxhook + nodeJS实现对微信数据的整合
后端