别再被 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个真实场景让你代码更优雅》

相关推荐
S***26751 小时前
基于SpringBoot和Leaflet的行政区划地图掩膜效果实战
java·spring boot·后端
芳草萋萋鹦鹉洲哦2 小时前
【elemen/js】阻塞UI线程导致的开关卡顿如何优化
开发语言·javascript·ui
1***s6323 小时前
Vue图像处理开发
javascript·vue.js·ecmascript
槁***耿3 小时前
JavaScript在Node.js中的事件发射器
开发语言·javascript·node.js
一叶茶3 小时前
移动端平板打开的三种模式。
前端·javascript
U***49833 小时前
JavaScript在Node.js中的Strapi
开发语言·javascript·node.js
@大迁世界3 小时前
相信我兄弟:Cloudflare Rust 的 .unwrap() 方法在 330 多个数据中心引发了恐慌
开发语言·后端·rust
5***g2983 小时前
新手如何快速搭建一个Springboot项目
java·spring boot·后端
老前端的功夫4 小时前
前端浏览器缓存深度解析:从网络请求到极致性能优化
前端·javascript·网络·缓存·性能优化
2***B4494 小时前
Rust在系统编程中的内存安全
开发语言·后端·rust