当前位置:

首页 > 编程开发 > 怎么通过 Arrays.stream().distinct() 极简实现对原始数组元素的去重与转换

怎么通过 Arrays.stream().distinct() 极简实现对原始数组元素的去重与转换

Arrays.stream().distinct()对引用类型数组直接去重,基本类型数组需装箱为包装流再操作,自定义对象必须重写equals和hashCode才能按值去重。可持续链式调用完成去重、映射与收集,实现简洁高效的数据处理。

一句话总结:Arrays.stream().distinct() 对引用类型数组天生有效,对基本类型需要先转包装流;自定义对象必须正确重写 equals 和 hashCode 才能按值去重;并且可以一条链式调用搞定去重、映射和收集。

很多人在处理数组去重时,第一个想到的就是 Arrays.stream().distinct()。但关键要看清楚:你传进去的“原始数组”是什么类型。对于 String[]、Integer[] 这类引用类型数组,它能直接识别出重复元素,一个 distinct() 就搞定了。可一旦换成 int[]、double[] 这样的基本类型数组,情况就变了——如果不做特殊处理,Stream 会傻乎乎地把整个数组当成一个对象来处理,根本不会去遍历里面的元素,更别说去重了。

怎么通过 Arrays.stream().distinct() 极简实现对原始数组元素的去重与转换

对引用类型数组:直接 distinct 即可

举个例子,String[] 或 Integer[] 这类数组,每个元素自带合理的 equals/hashCode 实现,distinct() 能按值去重,代码简洁直观:

String[] arr = {"a", "b", "a", "c"};
String[] unique = Arrays.stream(arr)
    .distinct()
    .toArray(String[]::new); // ["a", "b", "c"]

你甚至不需要写任何额外的比较逻辑,一行流操作就完成了去重与收集。

对基本类型数组:必须先升维或映射

当数组是 int[] 这类基本类型时,Arrays.stream() 返回的是 IntStream。好消息是 IntStream.distinct() 本身是有效的——但它返回的仍然是 IntStream。如果你想把它转回 int[],直接 .distinct().toArray() 就行。但更多场景下我们需要的是 Integer[] 或 List,这时就必须调用 boxed() 把基本类型装箱:

  • 转回 int[]:IntStream.distinct().toArray()
  • 转成 Integer[]:IntStream.distinct().boxed().toArray(Integer[]::new)
  • 转成 List:IntStream.distinct().boxed().collect(Collectors.toList())
int[] nums = {1, 2, 2, 3, 1};
int[] uniqueInts = Arrays.stream(nums).distinct().toArray();        // [1, 2, 3]
Integer[] uniqueBoxed = Arrays.stream(nums)
    .distinct()
    .boxed()
    .toArray(Integer[]::new);                                       // [1, 2, 3]

注意不要在 IntStream 上直接调用 .toArray(Integer[]::new),那会编译报错——必须先装箱。

注意 equals 语义:自定义对象要重写 equals & hashCode

对于自定义类(比如 User[]),distinct() 能去重的前提是该类正确重写了 equals() 和 hashCode()。否则即使两个对象内容完全相同,只要内存地址不同,就不会被当成重复元素移除。

看看反面例子:

User u1 = new User("Alice", 25);
User u2 = new User("Alice", 25); // 内容相同但不同对象
User[] users = {u1, u2};
// Arrays.stream(users).distinct().count() → 2(不是 1!)

这一点经常被忽略,但只要记住一条原则:任何需要按值比较的场景,都别忘记给自定义类实现 equals/hashCode,否则 distinct() 等于白用。

极简转换链:去重 + 映射 + 收集一步到位

实际开发中我们经常需要“先去重、再转换、最后收集”的一连串操作。这时候链式写法就体现出优势了:

String[] arr = {"hello", "world", "hello"};
List result = Arrays.stream(arr)
    .distinct()
    .map(String::toUpperCase)
    .collect(Collectors.toList()); // ["HELLO", "WORLD"]

这种写法清晰、不可变、没有副作用,是函数式去重转换的推荐范式。只要记住上述几个注意点(引用类型直接去重、基本类型先装箱、自定义对象重写 equals),你就能用 Arrays.stream().distinct() 把数组去重这件事做得简洁又优雅。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
作者最新文章
编程开发
相关文章 更多
c#如何使用FileStream_c#FileStream看这一篇就够了_保姆级教程
c#如何使用FileStream_c#FileStream看这一篇就够了_保姆级教程

FileStream适用于大文件、多进程共享及精确控制读写位置等场景,其构造函数需合理选择FileMode、FileAccess和FileShare参数。使用using确保及时释放句柄,避免文件占用。读写字符串时必须统一编码,否则会产生乱码。

c++如何读取内存中的压缩数据流_z_stream用法【深度】
c++如何读取内存中的压缩数据流_z_stream用法【深度】

使用z_stream解压内存数据需手动管理缓冲区与状态:先清零结构体,正确设置窗口位宽参数,然后循环调用inflate()函数直至返回Z_STREAM_END,期间动态扩容输出缓冲区,最后调用inflateEnd()清理,否则容易导致崩溃或数据不完整。

如何使用 ObjectOutputStream 序列化具有继承关系的复杂业务实体对象
如何使用 ObjectOutputStream 序列化具有继承关系的复杂业务实体对象

父类必须实现Serializable,否则子类序列化时抛出NotSerializableException异常;所有继承链上的类都应显式声明serialVersionUID,并遵循兼容性规则进行更新;transient和static字段在继承层次中同样影响序列化行为;构造函数在序列化过程中不会被调用,因此父类无参构造函数非必需。

C++实现字符串中单词的顺序翻转 _ 结合stringstream与reverse技巧【详解】
C++实现字符串中单词的顺序翻转 _ 结合stringstream与reverse技巧【详解】

使用std::stringstream按空格拆分单词存入vector,再通过std::reverse整体反转单词顺序,最后手动拼接并添加空格,注意避免首尾多余空格。该方法仅适用于ASCII字符串,不支持UTF-8等多字节字符,否则会因字节误分割导致乱码。

怎么利用 Stream.builder() 手动构建一个包含特定业务对象的流
怎么利用 Stream.builder() 手动构建一个包含特定业务对象的流

Stream.builder()适用于小批量确定值元素场景,需要先获取builder实例,通过add()逐个添加元素后调用build()生成流,泛型类型需显式指定。不适用于大批量填充,不建议转为并行流,但构建出的流支持limit、findFirst等常用短路操作。

怎么利用 Stream.anyMatch() 检查流中是否有满足条件的项
怎么利用 Stream.anyMatch() 检查流中是否有满足条件的项

anyMatch()是JavaStream的短路终端操作,当流中任意元素满足谓词时立即返回true,若流为空则返回false。请注意:不能与findFirst()或filter()链式调用,因为流被终端操作关闭后无法再次使用,会抛出异常。谓词内需防范null元素,应使用Objects.nonNull()判空以避免空指针异常。

如何利用 Stream.of() 快速构建一个简单的对象流
如何利用 Stream.of() 快速构建一个简单的对象流

Stream.of()适用于快速将多个明确对象转为流,避免集合中转。传数组会被视为单个元素,应改用Arrays.stream()或直接列元素。对null值应使用Stream.ofNullable()或手动判空。自定义对象流需注意覆盖基础方法,且流不可重复消费。

如何利用 Stream 的 parallelStream 配合自定义 ForkJoinPool 规避并行流对主线程池的阻塞
如何利用 Stream 的 parallelStream 配合自定义 ForkJoinPool 规避并行流对主线程池的阻塞

parallelStream默认使用全局共享的ForkJoinPool.commonPool,子任务阻塞会拖慢所有并行流。正确做法是创建自定义ForkJoinPool,将整个并行流作为任务提交执行。对I/O密集型任务,建议将阻塞操作包装进CompletableFuture,使用专用线程池分离职责。线程池并行度需根据任务类型合理设置,避免简单设为CPU核数。

Files.lines() 惰性读取:分析在处理 GB 级超大文本文件变量时利用 Stream 流规避内存溢出的策略
Files.lines() 惰性读取:分析在处理 GB 级超大文本文件变量时利用 Stream 流规避内存溢出的策略

Files.lines()看似惰性,但sorted()或collect()会全量加载导致OOM。安全用法:逐行forEach避免全量操作,用try-with-resources显式关闭并指定UTF-8编码,可结合缓冲批处理提升吞吐。

怎么通过 Stream.findAny() 在多核处理器上利用并行流优势快速碰撞出第一个匹配项
怎么通过 Stream.findAny() 在多核处理器上利用并行流优势快速碰撞出第一个匹配项

并行流findAny()利用多核并行与短路机制,任一线程找到结果立即终止,无需维护顺序,基于ForkJoinPool实现高效负载均衡。特别适用于数据量大且不关心顺序的场景,需通过parallelStream()启动才能触发并行处理,可显著提升性能。

查看更多
精品专题 更多
装机必备
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows
Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

PDF教程
PDF教程

正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

Mac软件 更多
Adobe Acrobat Pro macOS版
Adobe Acrobat Pro macOS版
Mac

Adobe Acrobat Pro 是面向办公、法务、财务、教育及出版用户的专业PDF处理软件,可在Mac上创建、编辑、转换、合并和保护文档,并提供OCR文字识别、表单、批注、内容比较、敏感信息遮盖及电子签名功能。

Blender
Blender
Windows、macOS 和 Linux

Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。

Shapr3D macOS版
Shapr3D macOS版
Mac

Shapr3D是一款面向工业设计、机械工程、建筑概念和三维打印工作流的CAD软件。Mac版采用Parasolid建模内核,支持草图约束、实体建模、工程图、可视化渲染及常见CAD格式交换,并可通过账户在多台设备之间同步项目。

WINDOWS 更多
AutoCAD Windows版
AutoCAD Windows版
Windows

AutoCAD 是 Autodesk 推出的专业计算机辅助设计软件,Windows 版支持精确二维绘图、三维实体与曲面建模、图纸标注、布局发布和任务自动化,并包含多套行业专业化工具组合,适用于建筑、机械、电气、工程建设及制造设计人员。

Adobe Acrobat Pro Windows版
Adobe Acrobat Pro Windows版
Windows

Adobe Acrobat Pro 是面向专业 PDF 工作的综合解决方案,可在 Windows 中创建、编辑、转换、比较、整理和保护文档,并支持表单、电子签名、扫描件文字识别及敏感信息永久遮盖。订阅还包含网页、移动服务和云端协作能力,

Blender
Blender
Windows、macOS 和 Linux

Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。