Collectors.toConcurrentMap() 是 Java 8 中创建线程安全 ConcurrentHashMap 的专用收集器,需指定 keyMapper、valueMapper,键冲突时必须提供 mergeFunction,可选 mapFactory 自定义实例,禁止 null 键值。

Collectors.toConcurrentMap() 是 Java 8 Stream API 中用于将流元素收集为 ConcurrentHashMap 的专用收集器,它生成的映射天然支持多线程安全读写,无需额外同步。
核心用法:基础签名与必要参数
该方法至少需要两个函数式参数:
-
keyMapper:定义每个元素如何生成键(
Function) -
valueMapper:定义每个元素如何生成值(
Function)
示例:将用户列表按 ID 构建并发映射
List<user> users = Arrays.asList(
new User(1L, "Alice"),
new User(2L, "Bob")
);
ConcurrentMap<long string> userMap = users.stream()
.collect(Collectors.toConcurrentMap(
User::getId, // keyMapper
User::getName // valueMapper
));</long></user>
处理键冲突:必须显式指定合并策略
当流中多个元素产生相同键时,toConcurrentMap 不会默认覆盖或抛异常,必须传入第三个参数 mergeFunction(BinaryOperator)来决定如何合并值。
- 常见做法是保留先出现的值:
(v1, v2) -> v1 - 或取后出现的值:
(v1, v2) -> v2 - 也可做聚合,如字符串拼接:
(v1, v2) -> v1 + "," + v2
示例(遇重复 ID 时保留第一个用户名):
ConcurrentMap<long string> safeMap = users.stream()
.collect(Collectors.toConcurrentMap(
User::getId,
User::getName,
(oldVal, newVal) -> oldVal // 冲突时保留旧值
));</long>
自定义并发映射工厂(可选)
第四个参数 mapFactory 允许指定具体的并发映射实现类(如调整初始容量、并发级别),例如:
ConcurrentMap<long string> tunedMap = users.stream()
.collect(Collectors.toConcurrentMap(
User::getId,
User::getName,
(v1, v2) -> v1,
() -> new ConcurrentHashMap(16, 0.75f, 4) // 初始容量16,负载因子0.75,并发级别4
));</long>
注意:传入的 Supplier 必须每次返回**新实例**,否则会导致不可预期行为。
注意事项与典型陷阱
- 键或值为
null会抛NullPointerException(ConcurrentHashMap不允许 null 键/值) - 不支持在收集过程中修改原始流源(如边遍历边删 List),这属于结构性修改,可能引发异常
- 虽然结果映射线程安全,但流本身的并行执行(
parallelStream())仍需确保keyMapper和valueMapper无副作用且线程安全 - 若只需线程安全读操作,普通
Collectors.toMap()+Collections.unmodifiableMap()更轻量;仅当需并发读写时才用toConcurrentMap











