☰
不必再造的轮子:Guava 集合、字符串、Table、缓存与事件总线的正确用法与避坑推演
2026/11/2 6:08:09 网站建设 项目流程

目录

一、先看清这只工具柜

(一)Guava 的定位与模块全景

(二)与 JDK 赛跑的二十年

(三)引入方式与版本选择

二、集合工具:从"能用"到"用对"

(一)不可变集合:防御性拷贝的终点

1、三种"只读"的本质区别

2、构建方式与 copyOf 的短路优化

3、拒收 null 与设计取舍

(二)列表:拼接、拆分、去重与分片

1、列表与字符串互转

2、去重的三种口径

3、惰性视图:Lists.transform 与 Lists.partition

(三)Map 家族:Multimap、BiMap、Multiset

1、Multimap:一键多值

2、BiMap:双向映射

3、Multiset:会计数的集合

4、Maps 工具:比对、索引与预估容量

(四)集合运算:视图的威力与陷阱

1、交集、并集、差集与对称差

2、视图会"活"着跟随源集合

3、子集、笛卡尔积、幂集与组合

4、业务场景:权限比对与标签同步

三、字符串:Joiner、Splitter、CharMatcher 与 Strings

(一)Joiner:可复用、线程安全的拼接器

(二)Splitter:比 String.split 更诚实

(三)CharMatcher:字符级的筛子

1、先选字符,再定动作

2、零宽字符的陷阱

3、性能提示:precomputed

(四)Strings 与 CaseFormat

(五)一条输入清洗流水线

四、数据流:FluentIterable、Iterables 与 Stream 的分工

(一)惰性求值的本质

(二)FluentIterable 与 Stream 的对照

(三)Iterables 的几把小刀

(四)链式处理的取舍

五、Table:二维映射的利器

(一)结构与视图

(二)四种实现的选型

1、HashBasedTable:通用首选

2、TreeBasedTable:行列有序

3、ArrayTable:稠密矩阵

4、ImmutableTable:构建一次,处处共享

(三)常见误区

1、往 Table 里放 null

2、用嵌套 Table 表达三维数据

3、把 Table 当数据库用

(四)实战:库存矩阵

六、Cache:本地缓存的正确姿势

(一)为什么不是 ConcurrentHashMap

(二)构建与加载

1、两种加载方式

2、加载器不能返回 null

(三)回收策略的真实行为

1、基于容量:近似 LRU 与分段

2、基于权重:淘汰的是最久未用,不是最重

3、基于时间:三种策略的区别

4、基于引用:weakKeys 的身份比较陷阱

5、组合策略的注意事项

(四)统计、监听与移除原因

(五)从 Guava Cache 到 Caffeine

七、EventBus:进程内发布订阅

(一)基本用法

(二)分发语义:同步、队列与异常

1、同步总线的分发顺序

2、异常不会传给调用方

3、线程模型与 AsyncEventBus

(三)官方为何不再推荐

八、工具柜里的其他抽屉

(一)Preconditions 与 Verify

(二)Range、RangeSet 与 RangeMap

(三)RateLimiter 与 Stopwatch

(四)Hashing 与 BloomFilter

(五)ListenableFuture 与并发小工具

九、落地:一张选型清单

(一)JDK 优先还是 Guava 优先

(二)依赖治理:冲突、BOM 与 shading

(三)团队规范与评审清单

十、结语

参考链接


干货分享,感谢您的阅读!

几乎每个 Java 项目里都躺着一个叫StringUtils、CollectionHelper或CommonUtil的类。它们大多从某次"顺手写一个"开始:把列表拼成逗号串,把逗号串拆回列表,给 Map 做个分组,再包一层带过期时间的ConcurrentHashMap当缓存。几年下来,这些类越长越胖,边界条件各写各的:有的吞掉 null,有的抛出 NPE,有的在尾部多出一个空串,有的在并发下加载了五十次数据库。

Google 开源的 Guava 就是为了终结这种局面而生的。它把 Google 内部多年沉淀的基础工具打包成一个库:不可变集合、多值映射、二维表、字符串拆分拼接、字符匹配、本地缓存、事件总线、区间、哈希、限流……几乎覆盖了"写业务代码时总要顺手造的那些轮子"。

但"拿来就用"只是第一步。很多团队用了 Guava 多年,依然会在几个地方反复摔跤:把Sets.intersection的返回值当成快照,往HashBasedTable里放 null,以为maximumSize(100)就一定能装 100 个,用weakKeys()缓存字符串键却永远取不到值,把 EventBus 当成跨模块解耦的银弹。这些问题在示例代码里看不出来,却会在线上悄悄出错。

这次我们换个讲法:每一类工具,先讲清它解决了什么问题,再用可运行的代码给出真实输出,最后把容易被忽略的语义差异和

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询