当前位置: 首页 > article >正文

Java Streams 使用教程

简介

StreamJava 8 引入的一个 函数式编程特性,可以让我们用声明式的方式操作集合(如 List、Set、Map 等)。

核心作用是:

  • 从集合中提取数据(流)

  • 对数据做中间操作(filter/map/sort...

  • 最后做终端操作(forEach/collect/count...

Stream 基础结构

collection.stream().filter(...)       // 中间操作.map(...)          // 中间操作.collect(...)      // 终结操作

创建 Stream 的方式

// 从集合创建
List<String> list = Arrays.asList("A", "B", "C");
Stream<String> stream1 = list.stream();// 从数组创建
Stream<Integer> stream2 = Arrays.stream(new Integer[]{1, 2, 3});// 使用 Stream.of()
Stream<String> stream3 = Stream.of("X", "Y", "Z");// 生成无限流(需限制)
Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 2).limit(10);// 数值范围
IntStream.range(1, 5);       // 生成 1,2,3,4
IntStream.rangeClosed(1,5);  // 生成 1,2,3,4,5// 文件生成
Stream<String> lines = Files.lines(Paths.get("data.txt")); // Builder 构建
Stream<String> customStream = Stream.<String>builder().add("Apple").add("Banana").build();

常用中间操作(返回 Stream)

  • filter(Predicate):条件过滤
list.stream().filter(s -> s.startsWith("A"))
  • map(Function):映射/转换
list.stream().map(String::toUpperCase)
  • flatMap(Function):拍平嵌套结构
list.stream().flatMap(List::stream)
  • distinct():去重
stream.distinct()
  • sorted():排序
stream.sorted(Comparator.reverseOrder())
  • limit(n):取前 n

  • skip(n):跳过前 n

  • peek(Consumer):调试用,查看中间结果

stream.peek(System.out::println)

示例

List<String> result = list.stream().filter(s -> s.startsWith("A")).map(String::toLowerCase).distinct().collect(Collectors.toList());

常用终止操作(返回非 Stream)

  • collect(Collector):收集为集合、字符串等
stream.collect(Collectors.toList())
  • forEach(Consumer):遍历每个元素
stream.forEach(System.out::println)
  • count():统计数量
stream.count()
  • anyMatch(Predicate):任一匹配
stream.anyMatch(s -> s.contains("a"))
  • allMatch():全部匹配

  • noneMatch():都不匹配

  • findFirst():找第一个元素

stream.findFirst()
  • findAny():找任意元素(并行时更快)

  • reduce():规约合并(累加、乘法等)

stream.reduce(0, Integer::sum)

示例

long count = list.stream().filter(s -> s.length() > 3).count();Optional<String> any = list.stream().findAny();String joined = list.stream().collect(Collectors.joining(", "));

收集器 Collectors 工具类

List<String> names = people.stream().map(Person::getName).collect(Collectors.toList());Set<String> set = list.stream().collect(Collectors.toSet());Map<String, Integer> map = people.stream().collect(Collectors.toMap(Person::getName, Person::getAge));String result = list.stream().collect(Collectors.joining(", "));double avg = people.stream().collect(Collectors.averagingInt(Person::getAge));

分组 & 分区

// 分组
Map<String, List<Person>> groupByDept = people.stream().collect(Collectors.groupingBy(Person::getDepartment));// 多级分组
Map<String, Map<Integer, List<Person>>> complexGroup =people.stream().collect(Collectors.groupingBy(Person::getDept, Collectors.groupingBy(Person::getAge)));// 分区(true/false 分两组)
Map<Boolean, List<Person>> partition = people.stream().collect(Collectors.partitioningBy(p -> p.getAge() > 30));

排序(sorted)

// 自然排序
list.stream().sorted().forEach(System.out::println);// 自定义排序
list.stream().sorted((a, b) -> a.length() - b.length()).forEach(System.out::println);// 对对象排序
people.stream().sorted(Comparator.comparing(Person::getAge).reversed()).forEach(System.out::println);

flatMap 的典型应用

List<String> lines = Arrays.asList("A B", "C D");
List<String> words = lines.stream().flatMap(line -> Arrays.stream(line.split(" "))).collect(Collectors.toList());

并行流(parallelStream)

list.parallelStream().forEach(System.out::println);

reduce 规约操作

int sum = Arrays.asList(1, 2, 3, 4).stream().reduce(0, Integer::sum); // 初始值 0,累加求和

应用案例

数据过滤与筛选

在处理大量数据时,常常需要依据特定条件筛选出符合要求的数据。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;public class DataFiltering {public static void main(String[] args) {List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);// 筛选出所有偶数List<Integer> evenNumbers = numbers.stream().filter(n -> n % 2 == 0).collect(Collectors.toList());System.out.println("偶数列表: " + evenNumbers);}
}
数据映射与转换

有时候需要把集合中的元素转换为其他类型或格式。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;class Person {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public int getAge() {return age;}
}public class DataMapping {public static void main(String[] args) {List<Person> people = Arrays.asList(new Person("Alice", 25),new Person("Bob", 30),new Person("Charlie", 35));// 将 Person 对象转换为他们的名字列表List<String> names = people.stream().map(Person::getName).collect(Collectors.toList());System.out.println("名字列表: " + names);}
}

运用 map 中间操作,把 Person 对象列表转换为包含每个人名字的字符串列表。

数据排序

利用 Streams 对集合中的元素进行排序。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;public class DataSorting {public static void main(String[] args) {List<String> words = Arrays.asList("banana", "apple", "cherry");// 按字母顺序排序List<String> sortedWords = words.stream().sorted().collect(Collectors.toList());System.out.println("排序后的单词列表: " + sortedWords);}
}

使用 sorted 中间操作对字符串列表按字母顺序进行排序。

数据统计

Stream 提供了一些方法用于统计数据,如求和、平均值、最大值、最小值等。

import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;public class DataStatistics {public static void main(String[] args) {List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);IntSummaryStatistics stats = numbers.stream().mapToInt(Integer::intValue).summaryStatistics();System.out.println("总和: " + stats.getSum());System.out.println("平均值: " + stats.getAverage());System.out.println("最大值: " + stats.getMax());System.out.println("最小值: " + stats.getMin());}
}

通过 summaryStatistics 方法,能够获取整数列表的总和、平均值、最大值和最小值等统计信息。

分组与分区

可以按照特定条件对数据进行分组或分区。

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;class Product {private String name;private double price;public Product(String name, double price) {this.name = name;this.price = price;}public String getName() {return name;}public double getPrice() {return price;}
}public class GroupingAndPartitioning {public static void main(String[] args) {List<Product> products = Arrays.asList(new Product("Apple", 1.5),new Product("Banana", 0.5),new Product("Cherry", 2.0),new Product("Date", 0.8));// 按价格是否大于 1 进行分区Map<Boolean, List<Product>> partitionedByPrice = products.stream().collect(Collectors.partitioningBy(p -> p.getPrice() > 1));System.out.println("价格大于 1 的产品: " + partitionedByPrice.get(true));System.out.println("价格小于等于 1 的产品: " + partitionedByPrice.get(false));}
}

最佳实践

  • 避免副作用:Stream 操作应是无状态的,避免修改外部变量。

  • 优先使用方法引用:使代码更简洁(如 String::length)。

  • 谨慎使用并行流:根据数据量和操作复杂度评估是否使用。

  • 链式操作顺序优化:将过滤操作(filter)放在前面,减少后续处理的数据量。

常见问题

  • Stream 不会修改源数据,操作是惰性的。

  • Stream 只能使用一次,一旦执行终端操作,流就被消费,不可重复使用。

  • Lambda 中处理 Stream 异常,或使用 try-catch 包裹终端操作。

Java Stream 与 C# LINQ

核心目标一致
特性Java Stream APIC# LINQ
面向语言Java 8+C# 3.0+
编程范式函数式编程集合查询式 + 函数式编程
处理方式面向流(Stream)处理面向集合(Enumerable/IQueryable)处理
核心思想用流水线的方式处理集合像 SQL 一样写集合操作
语法对比

基础例子:从字符串列表中过滤出以 A 开头的字母,转成小写后收集

  • Java Stream:
List<String> result = list.stream().filter(s -> s.startsWith("A")).map(String::toLowerCase).collect(Collectors.toList());
  • C# LINQ:
List<string> result = list.Where(s => s.StartsWith("A")).Select(s => s.ToLower()).ToList();

对比说明:两者几乎一致,Javastream() 后链接操作,C# 是直接链式调用。

常用操作对应表
功能Java StreamC# LINQ
过滤filter(Predicate)Where(Func<T, bool>)
映射map(Function)Select(Func<T, TResult>)
拍平flatMap(Function)SelectMany()
排序sorted() / ComparatorOrderBy() / ThenBy()
去重distinct()Distinct()
计数count()Count()
取前n条limit(n)Take(n)
跳过前n条skip(n)Skip(n)
查找元素findFirst() / findAny()FirstOrDefault() / First()
是否匹配anyMatch() / allMatch()Any() / All()
聚合reduce()Aggregate()
收集collect(Collectors)ToList() / ToDictionary()
分组Collectors.groupingBy()GroupBy()
分区Collectors.partitioningBy()GroupBy(bool) + ToLookup()
遍历forEach()foreach 或 .ForEach()(List 扩展)
使用方式差异
特性Java StreamC# LINQ
是否懒加载是,中间操作不执行直到终止操作是,延迟执行
多线程支持 .parallelStream()(需小心)可用 PLINQ(Parallel LINQ)并行处理
SQL 风格语法❌ 不支持✅ 支持 from ... where ... select 查询语法
集合类型支持Collection、数组、Map 等IEnumerable、IQueryable、List、Array 等
返回类型Stream → collect 后得集合LINQ 直接链式调用后转集合
示例对比:复杂操作
  • Java
Map<String, Map<Integer, List<Person>>> group =people.stream().collect(Collectors.groupingBy(Person::getDept,Collectors.groupingBy(Person::getAge)));
  • C#
var group = people.GroupBy(p => p.Dept).ToDictionary(g => g.Key,g => g.GroupBy(p => p.Age).ToDictionary(gg => gg.Key, gg => gg.ToList()));
并行处理实现
  • Java Streams:

通过 parallelStream()stream().parallel() 快速启用并行流,但需注意线程安全问题。

list.parallelStream().forEach(s -> process(s)); // 自动分配线程
  • C# PLINQ:

通过 AsParallel() 启用并行查询,可自定义并行度。

list.AsParallel().WithDegreeOfParallelism(4).ForAll(s => Process(s));
空值处理
  • Java Streams:

默认不支持 null 元素(可能抛出 NullPointerException),需显式处理。

  • C# LINQ:

允许集合中包含 null,但某些操作(如 First())可能需处理空值。

总结对比
维度Java Stream APIC# LINQ
可读性简洁,但不支持 SQL 风格支持 SQL 风格,阅读更直观
灵活性借助 Collectors 可以做很多操作LINQ 本身功能更丰富
多线程处理.parallelStream()(粗粒度)PLINQ(细粒度)
数据源支持Java 集合体系.NET 集合体系 + 数据库 IQueryable
底层机制基于中间操作链和终结操作基于延迟计算迭代器
功能扩展性使用 Collectors 辅助函数使用 LINQ Extension Methods
框架集成度和 Spring/Java EE 无缝结合和 Entity Framework、ASP.NET 配合良好

相关文章:

Java Streams 使用教程

简介 Stream 是 Java 8 引入的一个 函数式编程特性&#xff0c;可以让我们用声明式的方式操作集合&#xff08;如 List、Set、Map 等&#xff09;。 核心作用是&#xff1a; 从集合中提取数据&#xff08;流&#xff09; 对数据做中间操作&#xff08;filter/map/sort...&am…...

1001: 自由落体的计算

题目描述 一球从m米高度自由下落&#xff0c;每次落地后返回原高度的一半&#xff0c;再落下。 求它在第n次触地时会反弹多高&#xff1f;直到第n次触地时共经过多少米&#xff1f; 输入 一行,包含两个数m, n 其中0 < m < 1,000,000,000 0 < n < 1,000,000,000 输…...

开发环境解决浏览器层面跨域问题

适用于开发环境临时调试等情况 新建一个 Chrome 的快捷方式&#xff0c;目标后面跟上&#xff1a; –disable-web-security --disable-gpu --user-data-dir%LOCALAPPDATA%\Google\chromeTemp 打开后会给出不安全的提示...

2025年渗透测试面试题总结-拷打题库07(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 2025年渗透测试面试题总结-拷打题库07 1. CMS目录扫描的意义 2. 常见网站服务器容器 3. MySQL写入We…...

【leetcode刷题日记】lc.300-最长递增子序列

目录 1.题目 2.代码 1.题目 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0,3,1,6,2,…...

游戏引擎学习第236天:GPU 概念概述

回顾并展望通过视频采集卡进行流媒体传输的未来 昨天&#xff0c;我们迈出了大胆的一步&#xff0c;决定初始化硬件的 3D 加速&#xff0c;因为我有点厌倦了我们的游戏没有垂直同步&#xff08;vsync&#xff09;。如今&#xff0c;在 Windows 上&#xff0c;我找不到一种可靠…...

深入理解Linux中的线程控制:多线程编程的实战技巧

个人主页&#xff1a;chian-ocean 文章专栏-Linux 前言&#xff1a; POSIX线程&#xff08;Pthreads&#xff09; 是一种在 POSIX 标准下定义的线程库&#xff0c;它为多线程编程提供了统一的接口&#xff0c;主要用于 UNIX 和类 UNIX 系统&#xff08;如 Linux、MacOS 和 BS…...

【题解-Acwing】790. 数的三次方根

题目:790. 数的三次方根 题目描述 给定一个浮点数 n,求它的三次方根。 输入 共一行,包含一个浮点数 n 。 输出 共一行,包含一个浮点数,表示问题的解。 注意,结果保留 6 位小数。 数据范围 −10000 ≤ n ≤ 10000 时空限制 1s / 64MB 输入样例 1000.00输出样…...

【条形码识别改名工具】如何批量识别图片条形码,并以条码内容批量重命名,基于WPF和Zxing的开发总结

批量图片条形码识别与重命名系统 (WPF + ZXing)开发总结 项目适用场景 ​​电商商品管理​​:批量处理商品图片,根据条形码自动分类归档​​图书馆系统​​:扫描图书条形码快速建立电子档案​​医疗档案管理​​:通过药品条形码整理医疗图片资料​​仓储管理​​:自动化识…...

大模型微服务架构模块实现方案,基于LLaMA Factory和Nebius Cloud实现模型精调的标准流程及代码

以下是基于LLaMA Factory和Nebius Cloud实现模型精调的标准流程及代码示例&#xff0c;结合最新技术动态和行业实践整理&#xff1a; 一、LLaMA Factory本地部署方案 1. 环境配置 # 创建Python环境并安装依赖 conda create -n llama_factory python3.10 conda activate llam…...

【C++】 —— 笔试刷题day_22

一、添加字符 题目解析 这道题&#xff0c;给定两个字符串A和B&#xff0c;字符串A的长度要小于B的长度&#xff1b; 现在我们要对A字符串添加字符&#xff0c;使得A字符串长度等于B字符串的长度&#xff0c;并且要求对应位置的字母尽量相等&#xff0c;然后求出来不相等的字符…...

深入浅出:LDAP 协议全面解析

在网络安全和系统管理的世界中&#xff0c;LDAP&#xff08;轻量级目录访问协议&#xff0c;Lightweight Directory Access Protocol&#xff09;是一个不可忽视的核心技术。它广泛应用于身份管理、认证授权以及目录服务&#xff0c;尤其在企业级环境中占据重要地位。本文将从基…...

【Android面试八股文】Android应用进程的启动流程【二】

应用进程 1.1 Android系统进程的启动过程&#xff1a; 1、init进程fork出Zygote进程后&#xff0c;Zygote进程会创建一个服务端socket&#xff0c;等待AMS发起socket请求。 同时&#xff0c;由Zygote进程fork出的SystemServer进程会启动各项系统服务&#xff0c;其中就包含了A…...

“星睿O6” AI PC开发套件评测 - 部署PVE搭建All in One NAS服务器

Radxa O6平台上部署PVE搭建All in One NAS服务器 Radxa O6是一款性能卓越的单板计算机&#xff0c;其强劲的硬件配置和多样化的接口设计&#xff0c;使其成为家庭和小型企业理想的All in One服务器解决方案。值得一提的是&#xff0c;O6原生配备了两个5G网口&#xff0c;便于直…...

16.使用豆包将docker-compose的yaml转为k8s的yaml,安装各种无状态服务

文章目录 docker方式httpbinit-toolslinux-commandmyipreference docker-compose安装k8s方式 docker方式 httpbin A simple HTTP Request & Response Service https://httpbin.org/ https://github.com/postmanlabs/httpbin https://github.com/mccutchen/go-httpbin do…...

全志H5,NanopiKP1lus移植QT5.12记录

移植步骤 机器环境下载QT5.12.0源码安装交叉编译器修改qmake.conf文件配置编译选项qt5的configure选项说明基本配置选项编译器和链接器选项功能模块配置第三方库集成注意事项 配置过程报错解决配置完成编译过程报错解决编译完成将arm-qt文件夹传送到开发板配置板子环境变量运行…...

定制一款国密浏览器(10):移植SM2算法前,解决错误码的定义问题

上一章中,我给大家介绍了 SM4 在 BoringSSL 上的移植要点,本来计划本章介绍 SM2 算法的移植要点。在移植 SM2 过程中,遇到了一个拦路虎,所以先扫除这个拦路虎,这就是错误码的定义问题。 在铜锁中,引入了几个错误码和错误字符串,在文件 sm2_err.c 中: static const ER…...

使用EXCEL绘制平滑曲线

播主播主&#xff0c;你都多少天没更新了&#xff01;&#xff01;&#xff01;泥在干什么&#xff1f;你还做这个账号麻&#xff1f;&#xff01;&#xff01;&#xff01; 做的做的&#xff08;哭唧唧&#xff09;&#xff0c;就是最近有些忙&#xff0c;以及…… 前言&…...

Warcraft Logs [Classic] [WCL] Usage Wizard <HTOC>

‌HTOC&#xff08;十字军的试炼&#xff09;副本中各个BOSS的ID如下‌&#xff1a; ‌629 - 诺森德野兽‌ ‌633 - 加拉克苏斯大王‌ ‌637 - 派系冠军‌ ‌641 - 瓦格里双子‌ ‌645 - 阿努巴拉克‌ encounterID!637 and encounterID!641 encounterID NOT IN (637,641) 伤害 …...

【笔记】网络安全管理

计算机硬件中&#xff0c;运算器和控制器通常集成在一块芯片内&#xff0c;一般称为&#xff08;&#xff09;。 数据库DB、数据库系统DBS、数据库管理系统DBMS&#xff0c;三者之间的关系是&#xff08;&#xff09;。 OSI/RM体系结构中的网络层与TCP/IP体系结构中的&#x…...

在服务器上部署MinIO Server

MinIO的优势 高性能&#xff1a;MinIO号称是目前速度最快的对象存储服务器&#xff0c;据称在标准硬件上&#xff0c;对象存储的读/写速度最高可以高达183 GB/s和171 GB/s&#xff0c;可惜我的磁盘跟不上 兼容性&#xff1a;MinIO基于Amazon S3协议&#xff0c;并提供了与S3兼…...

一个改善Entity Framework异常处理和错误信息的开源项目

使用DDD从零构建一个完整的系统 使用Entity Framework作为ORM框架应该是绝大多数项目的选择&#xff0c;使得我们操作数据库变得简单方便&#xff1b;但是我们操作数据库&#xff0c;绝对是无法避免数据库发生异常的情况&#xff0c;数据库针对每一种异常也都会提供一个编码来…...

计算机视觉——基于 Yolov8 目标检测与 OpenCV 光流实现目标追踪

1. 概述 目标检测&#xff08;Object Detection&#xff09;和目标追踪&#xff08;Object Tracking&#xff09;是计算机视觉中的两个关键技术&#xff0c;它们在多种实际应用场景中发挥着重要作用。 目标检测指的是在静态图像或视频帧中识别出特定类别的目标对象&#xff0…...

PHP使用pandoc把markdown文件转为word

文章目录 首先安装pandocPHP处理 服务器操作系统是Linux&#xff0c;centos 首先安装pandoc yum install -y pandoc安装完成后输入如下代码&#xff0c;检查安装是否成功 pandoc --versionPHP处理 我把markdown内容存到了数据库里&#xff0c;所以要从数据库读取内容。对内容…...

第二十四天 - 分布式任务队列 - Celery高级应用 - 练习:分布式监控任务系统

一、Celery核心机制解析 1.1 分布式架构四要素 # celery_config.py BROKER_URL redis://:passwordlocalhost:6379/0 # 消息中间件 RESULT_BACKEND redis://:passwordlocalhost:6379/1 # 结果存储 TASK_SERIALIZER json ACCEPT_CONTENT [json] TIMEZONE Asia/Shanghai核…...

针对MCP认证考试中的常见技术难题进行实战分析与解决方案分享

一、身份与权限管理类难题 场景1&#xff1a;Active Directory组策略&#xff08;GPO&#xff09;不生效 问题现象&#xff1a;客户端计算机未应用新建的组策略。排查步骤&#xff1a; 检查GPO链接顺序&#xff1a;使用gpresult /r查看策略优先级&#xff0c;确保目标OU的GPO…...

【滑动窗口】最⼤连续 1 的个数 III(medium)

⼤连续 1 的个数 III&#xff08;medium&#xff09; 题⽬描述&#xff1a;解法&#xff08;滑动窗⼝&#xff09;&#xff1a;算法思路&#xff1a;算法流程&#xff1a; C 算法代码&#xff1a;Java 算法代码&#xff1a; 题⽬链接&#xff1a;1004. 最⼤连续 1 的个数 III …...

OBS 日期时间.毫秒时间脚本 date-and-time.lua

文章目录 OBS 日期时间.毫秒时间脚本&#xff1a;效果 OBS 日期时间.毫秒时间脚本&#xff1a; obs obslua source_name ""last_text "" format_string "" activated false-- 此函数用于获取精确的毫秒级时间戳&#…...

探索大语言模型(LLM):目标、原理、挑战与解决方案

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言语言模型的目标语言模型的数学表示语言模型面临的挑战解决参数量巨大的方法1. 马尔可夫假设2. 神经网络语言模型3.自监督学习4. 分布式表示 脑图总结 前言 在自…...

ES基本操作(Java API)

1. 导入restClient依赖 <!-- es --><dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.12.1</version></dependency> <!…...