Guava不可变集合无public构造器,须用静态工厂方法创建,如ImmutableList.of()或copyOf(),且修改操作抛UnsupportedOperationException;Multimap简化嵌套列表管理但不继承Map;Stream应直接collect(ImmutableList.toImmutableList());ImmutableList不实现JDK21 SequencedCollection。

ImmutableList、ImmutableSet 为什么不能直接 new
Guava 的不可变集合不是靠 final 修饰的普通集合,而是全新构造的只读实现。你写 new ImmutableList() 会编译失败——它没有 public 构造器。
正确入口只有静态工厂方法,核心是「构建即冻结」逻辑:一旦生成,任何修改操作(如 add()、remove())都会抛 UnsupportedOperationException。
- 用
ImmutableList.of("a", "b")创建小固定集合(最多 5 个元素) - 超过 5 个或需要从已有集合转换,用
ImmutableList.copyOf(list);注意传入 null 会直接 NPE,建议先判空 -
ImmutableSet.copyOf(collection)对重复元素自动去重,但不保证顺序(底层用ImmutableHashSet),要有序用ImmutableSortedSet
Multimap 代替 Map> 的真实代价
写 Map<string list>></string> 手动管理嵌套列表很麻烦:每次 put 前得检查 key 是否存在、list 是否为空、是否要 new ArrayList。而 Multimap 把这事封装掉了,但代价是它不继承 Map 接口,不能直接当 Map 用。
- 常用的是
ArrayListMultimap.create()(值按插入顺序)和HashMultimap.create()(值无序,内存更省) -
put("k1", 1)和put("k1", 2)后,get("k1")返回的是不可修改的Collection视图,不能调clear()或remove()—— 想删某个值得用remove("k1", 1) - 如果需要支持 null key 或 null value,必须选
LinkedHashMultimap或显式 wrap,因为默认实现禁止 null
ImmutableList.copyOf() 在流式处理中容易误踩的坑
很多人在 Stream 后接 collect(Collectors.toList()),再传给 ImmutableList.copyOf(),以为双重保险。其实没必要,还多一次遍历。
立即学习“Java免费学习笔记(深入)”;
- Stream 本身有
toList()(Java 16+),返回的是不可变 List,但它是 JDK 实现,和 Guava 无关;Guava 的ImmutableList.toImmutableList()才是配套收集器 - 错误写法:
stream.collect(Collectors.toList()).stream().collect(ImmutableList.toImmutableList())—— 白跑两轮 - 正确写法:
stream.collect(ImmutableList.toImmutableList()),且该收集器内部做了短路优化,遇到 null 元素会立即报NullPointerException,不是延迟到遍历才崩 - 如果 stream 可能为空,
toImmutableList()返回的是空的ImmutableList,不是 null,这点比自己 new ArrayList 安全
Guava 集合和 JDK 21+ SequencedCollection 的关系
Java 21 引入了 SequencedCollection,让 LinkedList、ArrayDeque 等支持统一的 getFirst()/getLast()。但它和 Guava 的不可变集合没交集——Guava 的 ImmutableList 不实现这个接口,JDK 也没计划让它实现。
- 这意味着:你不能对
ImmutableList调用getFirst(),即使它内部是数组实现;想取首尾只能用get(0)和get(size() - 1),并自己判空 - 如果你的代码同时依赖 JDK 新 API 和 Guava,别假设行为兼容;比如
SequencedCollection.reversed()返回的是新视图,而ImmutableList.reverse()是真正新建一个反序副本,内存开销不同 - 目前最稳的混用方式:把 Guava 集合作为数据源,转成 JDK 接口(如
list.stream())再进新 API 流程
不可变性和多值映射的边界很清晰,但具体到每个工厂方法的 null 处理、空集合返回值、以及和 JDK 新特性的错位,才是真正写代码时卡住人的地方。










