别再被 Stream.toMap() 劝退了!3 个真实避坑案例,建议收藏

大家好,我是大华。 最近在公司做代码review的时候,几个同事在使用Stream.toMap()时踩了坑。有的甚至直接说:"这玩意儿太坑了,我宁愿写 for 循环!"

其实toMap()没那么可怕,今天分享3个避坑案例。看完你也就能放心用了!

1. 重复key直接报错

那天小王写了个这样的代码:

java 复制代码
List<User> userList = Arrays.asList(
    new User(1, "张三"),
    new User(2, "李四"),
    new User(1, "王五")  // 注意:重复的ID
);
// 转map
Map<Integer, String> map = userList.stream()
    .collect(Collectors.toMap(User::getId, User::getName));

一运行,直接崩了!抛出一堆Duplicate key的异常。

解决方案:加个合并函数就行

java 复制代码
Map<Integer, String> map = userList.stream()
    .collect(Collectors.toMap(
        User::getId, 
        User::getName,
        (oldValue, newValue) -> oldValue // 重复时保留旧值
    ));

效果对比原代码 :直接抛出异常Duplicate key 张三(attempted merging values 张三 and 王五)解决后 :成功生成Map,内容为{1=张三, 2=李四}(保留了第一个出现的值)。

这样当key重复时,会自动处理而不是直接报错。 根据需求,你也可以选择覆盖:(oldValue, newValue) -> newValue,这样结果就会是{1=王五, 2=李四}(保留最后一个值)

2. 空指针异常

小李遇到了更头疼的问题:

java 复制代码
List<Product> products = getProducts(); // 可能返回null值列表
Map<Long, String> productMap = products.stream()
    .collect(Collectors.toMap(Product::getId, Product::getName));

如果列表里有null元素,直接NullPointerException

解决方案: 先用filter过滤掉null

java 复制代码
Map<Long, String> productMap = products.stream()
    .filter(Objects::nonNull)  // 先过滤null
    .collect(Collectors.toMap(
        Product::getId, 
        Product::getName,
        (oldValue, newValue) -> newValue
    ));

效果对比原代码 :遇到null元素直接抛出NullPointerException解决后 :自动跳过null元素,只处理有效数据生成Map

这样简单的一步,就可以告别空指针!

3. 想要转换特定Map类型

小张需要返回一个有序的LinkedHashMap,但toMap()默认返回HashMap,怎么办?

解决方案: 指定具体Map类型

java 复制代码
Map<Integer, User> userMap = userList.stream()
    .filter(Objects::nonNull)
    .collect(Collectors.toMap(
        User::getId,
        Function.identity(),  // 直接取对象本身
        (oldValue, newValue) -> newValue,
        LinkedHashMap::new  // 指定Map类型
    ));

效果对比原代码 :返回HashMap,遍历顺序不确定。 解决后 :返回LinkedHashMap,保持元素插入顺序,比如:

java 复制代码
// 遍历时保证按 张三、李四、王五的顺序
userMap.forEach((id, user) -> System.out.println(user.getName()));

这样就能得到保持插入顺序的LinkedHashMap了。

总结

toMap()其实很好用,只要记住这三个点就可以:

  1. 有重复key时:记得加合并函数(oldValue, newValue) -> ...
  2. 可能有空元素时:先用filter(Objects::nonNull)过滤
  3. 需要特定Map类型时:第四个参数指定如LinkedHashMap::new

以后再遇到toMap(),就不用绕道走了。这几个技巧掌握后,你就能优雅地使用它了! PS: 文中代码基于Java8+,如果你用的是旧版本...建议升级,很多新特性真的很好用!

觉得有帮助的话,点个收藏分享给更多小伙伴吧~还有什么问题欢迎留言讨论!

我是大华,专注分享前后端开发的实战笔记。关注我,少走弯路,一起进步!

📌往期精彩

《工作 5 年没碰过分布式锁,是我太菜还是公司太稳?网友:太真实了!》

《写给小公司前端的 UI 规范:别让页面丑得自己都看不下去》

《只会写 Mapper 就敢说会 MyBatis?面试官:原理都没懂》

《别学23种了!Java项目中最常用的6个设计模式,附案例》

《Vue3+TS设计模式:5个真实场景让你代码更优雅》

相关推荐
华仔啊2 小时前
别再写 TypeScript enum了!新枚举方式让 bundle 瞬间小20%
javascript·typescript
夕颜1112 小时前
让 Cursor 教我写插件
后端
方安乐2 小时前
vite+vue+js项目使用ts报错
前端·javascript·vue.js
郭京京2 小时前
goweb内置的响应2
后端·go
njsgcs2 小时前
网页连接摄像头
javascript·css·html
李明卫杭州2 小时前
JavaScript 中的各种取整方式详解
javascript
小猪乔治爱打球2 小时前
[Golang 修仙之路] Go语言:内存管理
后端·面试
几颗流星2 小时前
Rust 常用语法速记 - 循环
后端·rust