Java进阶——Stream流以及常用方法详解

        本文详细介绍了 Java Stream 流的重要知识点。包括数据源与操作分离(不存储数据,不可复用)、惰性求值与短路优化;以及流的创建方式,如集合创建、数组 / 值创建、文件创建;然后介绍中间操作,像过滤与切片等;还涉及终止操作、集合归约与 Collectors 工具类、并行流与线程安全、性能优化与日常工作中使用Java Stream的注意点等等。

本文目录

    • 一、Stream核心概念
      • 1. 数据源与操作分离
      • 2. 惰性求值与短路优化
    • 二、流的创建方式
      • 1. 集合创建
      • 2. 数组/值创建
      • 3. 文件
    • 三、中间操作
      • 1. 过滤与切片
      • 2. 映射
      • 3. 排序
      • 4. 观察中间结果
    • 四、终止操作
      • 1. 匹配与查找
      • 2. 归约与统计
      • 3. 遍历与消费
    • 五、集合归约与Collectors工具类
      • 1. 常用收集器
      • 2. 分组与分区
      • 3. 统计与连接
    • 六、并行流与线程安全
      • 并行流使用
    • 七、日常使用注意点
      • 1. 避免重复创建流
      • 2. 优先选择基本类型流
      • 3. 短路操作优化
    • 八、日常工作实战案例
      • 1. 订单金额统计
      • 2. 商品筛选与排序
      • 3. 用户行为分析

一、Stream核心概念

1. 数据源与操作分离

        Stream不存储数据,仅对数据源(如集合、数组、I/O)进行计算。需要注意的是,流是不可复用的,一旦流被消费,就不能再次使用,否则会抛出IllegalStateException异常。

2. 惰性求值与短路优化

  • 中间操作(如filtermap)是延迟执行的,只有当遇到终止操作(如collect)时才会触发计算。
  • 短路操作(如findFirstanyMatch)可以提前终止遍历,减少不必要的计算。


二、流的创建方式

1. 集合创建

List<String> list = Arrays.asList("a", "b");
Stream<String> stream = list.stream(); // 顺序流
Stream<String> parallelStream = list.parallelStream(); // 并行流

2. 数组/值创建

Stream<String> stream1 = Stream.of("a", "b");
Stream<String> stream2 = Arrays.stream(new String[]{"a", "b"});

3. 文件

Stream<String> lines = Files.lines(Paths.get("data.txt")); // 读取文件



三、中间操作

1. 过滤与切片

  • filter(Predicate):用于过滤元素。
  • distinct():去除重复元素。
  • limit(n):截断前n个元素。
  • skip(n):跳过前n个元素。

2. 映射

  • map(Function):一对一转换,提取对象的某个字段。
  • flatMap(Function):扁平化操作,可将List<List<T>>转为List<T>

3. 排序

  • sorted():自然排序。
  • sorted(Comparator):自定义排序。

4. 观察中间结果

.peek(e -> System.out.println("Processing: " + e)) 



四、终止操作

1. 匹配与查找

  • anyMatch(Predicate):判断是否有任一元素满足条件。
  • allMatch(Predicate):判断是否所有元素都满足条件。
  • findFirst():返回第一个元素(返回类型为Optional)。
  • findAny():返回任意元素,在并行流中更高效。

2. 归约与统计

  • reduce(BinaryOperator):用于聚合操作,如求和。
  • collect(Collectors):将流转换为集合(如List、Map)。
  • count():统计元素总数。
  • max(Comparator)/min(Comparator):找出元素的极值。

3. 遍历与消费

  • forEach(Consumer):遍历元素,无顺序保证。
  • forEachOrdered(Consumer):按顺序遍历元素。


五、集合归约与Collectors工具类

1. 常用收集器

List<String> list = stream.collect(Collectors.toList());
Set<String> set = stream.collect(Collectors.toSet());
Map<String, User> map = stream.collect(Collectors.toMap(User::getId, Function.identity()));

2. 分组与分区

// 按年龄分组
Map<Integer, List<User>> ageGroup = users.stream().collect(Collectors.groupingBy(User::getAge));// 跟据年龄是否>=18进行分区
Map<Boolean, List<User>> partition = users.stream().collect(Collectors.partitioningBy(u -> u.getAge() >= 18));

3. 统计与连接

Double average = users.stream().collect(Collectors.averagingInt(User::getAge)); // 平均年龄String names = users.stream().map(User::getName).collect(Collectors.joining(", ")); // 拼接字符串



六、并行流与线程安全

并行流使用

List<Integer> result = list.parallelStream().filter(n -> n % 2 == 0).collect(Collectors.toList());



七、日常使用注意点

1. 避免重复创建流

错误示例:

for (int i = 0; i < 10; i++) {list.stream().filter(...); // 多次创建流
}

2. 优先选择基本类型流

IntStreamLongStreamDoubleStream可以避免装箱开销:

IntStream.range(0, 100).sum(); // 比Stream<Integer>高效

3. 短路操作优化

尽早使用limitfindFirst等操作可以减少计算量:

users.stream().filter(u -> u.getAge() > 30).findFirst() // 找到第一个符合条件后即终止.orElse(null);



八、日常工作实战案例

1. 订单金额统计

// 计算所有订单总金额
double totalAmount = orders.stream().mapToDouble(Order::getAmount).sum();// 按用户分组统计消费总额
Map<Long, Double> userTotal = orders.stream().collect(Collectors.groupingBy(Order::getUserId,Collectors.summingDouble(Order::getAmount)));

2. 商品筛选与排序

// 筛选库存>0的商品并按价格排序
List<Product> availableProducts = products.stream().filter(p -> p.getStock() > 0).sorted(Comparator.comparing(Product::getPrice)).collect(Collectors.toList());

3. 用户行为分析

// 统计最近一周活跃用户数
long activeUsers = userLogs.stream().filter(log -> log.getAction().equals("LOGIN")).filter(log -> log.getTime().isAfter(LocalDateTime.now().minusDays(7))).map(UserLog::getUserId).distinct().count();

在日常开发中,合理运用Stream流可以让代码更加简洁、高效,提高开发效率。希望本文对你有所帮助!



← 上一篇 Java进阶——数据类型深入解析
记得点赞、关注、收藏哦!
下一篇 Java进阶——注解一文全懂 →

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/25775.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

绕过密码卸载360终端安全管理系统

一不小心在电脑上安装了360终端安全管理系统&#xff0c;就会发现没有密码&#xff0c;就无法退出无法卸载360&#xff0c;很容易成为一个心病&#xff0c;360终端安全管理系统&#xff0c;没有密码&#xff0c;进程无法退出&#xff0c;软件无法卸载&#xff0c;前不久听同事说…

MongoDB 笔记

一、基础概念 MongoDB 的特点是什么&#xff1f; MongoDB是一种NoSQL数据库&#xff0c;具有以下特点&#xff1a; 文档存储模型 MongoDB 使用 BSON&#xff08;Binary JSON&#xff09; 格式存储数据&#xff0c;数据以文档的形式组织&#xff0c;类似于JSON对象。文档可以包…

小程序Three Dof识别 实现景区AR体验

代码工程 GitCode - 全球开发者的开源社区,开源代码托管平台 dof

ABAP语言的动态程序

通过几个例子&#xff0c;由浅入深讲解 ABAP 动态编程。ABAP 动态编程主要通过 RTTS (Runtime Type Services) 来实现&#xff0c;包括 RTTI 和 RTTC: 运行时类型标识&#xff08;RTTI&#xff09; – 提供在运行时获取数据对象的类型定义的方法。运行时类型创建&#xff08;R…

【安卓】BroadcastReceiver 动态声明为 RECEIVER_NOT_EXPORTED 后无法接收任何 Intent 的问题

一、问题起因 自 Android 14 (API 级别 34) 起&#xff0c;使用 context.registerReceiver(receiver, filter, flags) 动态注册广播接收器时&#xff0c;必须显式地声明 RECEIVER_NOT_EXPORTED 或 RECEIVER_EXPORTED 。 如果声明为 RECEIVER_EXPORTED &#xff0c;任何第三方应…

unity pico开发二:创建基本的交互

文章目录 导入UnityXR Interaction ToolKit构建基础内容 导入UnityXR Interaction ToolKit 检查一下packagemanager&#xff0c;unityxr interactionToolkit是否自动导入 我们需要升级到一个不超过3.x的版本&#xff0c;因为pico还不支持3.x的内容 然后右侧samples里导入初始…

[STM32]从零开始的STM32 DEBUG问题讲解及解决办法

一、前言 最近也是重装了一次keil&#xff0c;想着也是重装了&#xff0c;也是去官网下载了一个5.41的最新版&#xff0c;在安装和配置编译器和别的版本keil都没太大的区别&#xff0c;但是在调试时&#xff0c;遇到问题了&#xff0c;在我Debug的System Viewer窗口中没有GPIO&…

学习threejs,使用ShaderMaterial自定义着色器材质

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.ShaderMaterial1.1.1…

查看ITHOR全部仿真家庭场景

1. 目标 按序号显示所有120个家庭场景统计单个场景里物体数量 2. 代码 import time from ai2thor.controller import Controller# 统计当前场景中的物体数量 def count_objects_in_scene(controller):objects controller.last_event.metadata["objects"]object_c…

ES6 特性全面解析与应用实践

1、let let 关键字用来声明变量&#xff0c;使用let 声明的变量有几个特点&#xff1a; 1) 不允许重复声明 2) 块儿级作用域 3) 不存在变量提升 4) 不影响作用域链 5) 暂时性死区 6&#xff09;不与顶级对象挂钩 在代码块内&#xff0c;使用let命令声明变量之前&#x…

VSCode轻松调试运行C#控制台程序

1.背景 我一直都是用VS来开发C#项目的&#xff0c;用的比较顺手&#xff0c;也习惯了。看其他技术文章有介绍VS Code更轻量&#xff0c;更方便。所以我专门花时间来使用VS Code&#xff0c;看看它是如何调试代码、如何运行C#控制台。这篇文章是一个记录的过程。 2.操作 2.1 V…

【多模态】Magma多模态AI Agent

1. 前言 微软杨建伟团队&#xff0c;最近在AI Agent方面动作连连&#xff0c;前两天开源了OmniParser V2&#xff0c;2月26日又开源了Magma&#xff0c;OmniParser专注在对GUI的识别解析&#xff0c;而Magma则是基于多模态技术&#xff0c;能够同时应对GUI和物理世界的交互&…

spring Boot入门

目录 Spring Boot 概述 新建Spring Boot项目 方式一&#xff1a;使用Spring Initializr创建SpringBoot项目 方式二&#xff1a;使用Maven方式构建Spring Boot项目 Spring Boot 概述 简介 •Spring Boot是基于Spring框架开发的全新框架&#xff0c;其设计目的是简化Java…

手机隐私数据彻底删除工具:回收或弃用手机前防数据恢复

软件介绍 有这样一款由吾爱网友chenwangjun 原创开发的数据处理软件&#xff0c;名为 AndroidDiskClear。它的核心功能十分强大&#xff0c;能够将你手机里已经删除的各类文件&#xff0c;像图片、普通文件、文字信息等彻底清除干净&#xff0c;有效杜绝数据恢复类软件的二次恢…

docker使用代理的简单配置

1准备代理服务器 准备代理服务器&#xff0c;例如192.168.120.168:52209 配置docker.service文件 查看service文件的位置 systemctl status docker 编辑service文件 vim /usr/lib/systemd/system/docker.service 添加代理配置 ... [Service] Environment"HTTP_PROXY…

Coze与Dify:企业级大模型应用开发认知陷阱与破局之道

前言 当前大模型应用开发似乎陷入了一种“范式陷阱”&#xff1a;当人们谈论AI Agent或智能体时&#xff0c;脑海里浮现的往往是Coze、Dify这类以对话交互为核心的低代码平台。这些工具确实降低了体验大模型的门槛&#xff0c;但也让行业陷入一种危险的认知偏差——将大模型等…

GitHub 语析 - 基于大模型的知识库与知识图谱问答平台

语析 - 基于大模型的知识库与知识图谱问答平台 GitHub 地址&#xff1a;https://github.com/xerrors/Yuxi-Know &#x1f4dd; 项目概述 语析是一个强大的问答平台&#xff0c;结合了大模型 RAG 知识库与知识图谱技术&#xff0c;基于 Llamaindex VueJS FastAPI Neo4j 构…

由浅入深系列——Distinctive Image Featuresfrom Scale-Invariant Keypoints(SIFT)

第一章&#xff1a;为什么我们需要"图像指纹"&#xff1f;——SIFT的诞生 想象一下&#xff0c;你带着一张埃菲尔铁塔的明信片来到巴黎。站在铁塔脚下&#xff0c;你举起明信片想拍张对比照——但无论怎么调整角度&#xff0c;手机APP就是识别不出两张图片的对应关系…

spring注解开发(Spring整合MyBatis——Mapper代理开发模式、(Spring、MyBatis、Jdbc)配置类)(6)

目录 一、纯MyBatis独立开发程序。 &#xff08;1&#xff09;数据库与数据表。 &#xff08;2&#xff09;实体类。 &#xff08;3&#xff09;dao层接口。&#xff08;Mapper代理模式、无SQL映射文件——注解配置映射关系&#xff09; &#xff08;4&#xff09;MyBatis核心配…

Redis缓存一致性难题:如何让数据库和缓存不“打架”?

标题&#xff1a;Redis缓存一致性难题&#xff1a;如何让数据库和缓存不“打架”&#xff1f;&#xff08;附程序员脱发指南&#xff09; 导言&#xff1a;当数据库和缓存成了“异地恋” 想象一下&#xff1a;你刚在美团下单了一份麻辣小龙虾&#xff0c;付款后刷新页面&#…