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

告别循环!用Stream优雅处理集合

什么是stream?

也叫Stream流,是jdk8新增的一套API(java.util.stream.*)可以用于操作集合或者数组的数据。

优势:Stream流大量的结合了Lambda语法的风格编程,提供了一种更加强大,更加简单的方式操作或者数组中的数据,代码更简洁,可读性更好。

体验Stream流

在这里插入图片描述

原来的操作方法

ArrayList<String> list1 = new ArrayList<String>();
list1.add("赵无极");
list1.add("赵敏");
list1.add("张双");
list1.add("张三a");
list1.add("周娅");
//1.把所有以“张”开头的元素存储到新集合中
ArrayList<String> list2 = new ArrayList<>();
for(String name : list1){if(name.startsWith("张")){list2.add(name);}
}
System.out.println(list2);
//把“张”开头的,长度为3的元素再存储到新集合中
ArrayList<String> list3 = new ArrayList<>();
for(String name : list2){if(name.length() == 2){list3.add(name);}
}
System.out.println(list3);

是不是很繁琐,那我们就用Stream流来试一下。

我们先拿到这个集合,去调它的一个方法叫stream,得到Stream流方法,而它也支持链式编程的,可以继续用点(.)来调用它的方法,调用filter方法,这个方法的作用是过滤。

list1.stream().filter(name->name.startsWith("张")).filter(name->name.length()==3).forEach(name->System.out.println(name));
  1. list1.stream()
    

    list1集合转换成一个流。流是Java 8引入的一个抽象概念,它可以对集合进行各种高效的聚合操作。

  2. .filter(name->name.startsWith("张"))
    

    使用filter方法对流中的元素进行筛选。name->name.startsWith("张")是一个Lambda表达式,它定义了一个谓词(Predicate),用于检查每个元素(这里是name)是否以"张"开头。只有满足这个条件的元素才会被保留在流中。

  3. .filter(name->name.length()==3)
    

    再次使用filter方法对已经筛选过的流进行进一步筛选。这次的筛选条件是元素的长度是否等于3。同样,只有满足这个条件的元素才会被保留在流中。

  4. .forEach(name->System.out.println(name))
    

    使用forEach方法对筛选后的流中的每个元素执行操作。name->System.out.println(name)是一个Lambda表达式,它定义了对每个元素执行的操作,即打印出每个元素。

Stream流的使用步骤

图片的形式展示

在这里插入图片描述

常见方法

如何获取Stream流?

获取集合的Stream流

//Collection提供的如下方法
default Stream<E> stream();

获取数组的Stream流

//Arrays类提供的如下方法
public static <T> stream(T[] array);
//Stream类提供的如下方法
public static Stream<T> of(T...values);

例题

1.如何获取List集合的Stream流?

List<String> names = new ArrayList<>();
Collections.addAll(names,"张三丰","张无忌","周志","赵明");
Stream<String> stream = names.stream();
stream.filter(n -> n.length()>2).forEach(n -> System.out.println(n));//张三丰 张无忌

2.如何获取Set集合的Stream流?

Set<String> set = new HashSet<>();
Collections.addAll(set,"张三丰","张无忌","周志","赵明");
Stream<String> stream1 = set.stream();
stream1.filter(n -> n.contains("三")).forEach(n -> System.out.println(n));//张三丰

3.如何获取Map集合的Stream流?

Map集合不能直接使用stream调用Stream流,因为Stream方法是Collection提供的,Map集合不属于Collection。

  1. keySet(): 返回映射中包含的键的Set视图。此方法返回的集合支持通过流操作处理映射中的所有键。
  2. values(): 返回映射中包含的值的Collection视图。此方法返回的集合支持通过流操作处理映射中的所有值。
  3. entrySet(): 返回映射中包含的键值对的Set视图。此方法返回的集合支持通过流操作处理映射中的所有键值对(Map.Entry)。
Map<String, String> map = new HashMap<>();
map.put("张三", "30");
map.put("李四", "25");
map.put("张伟", "35");
map.put("王五", "40");// 对Map的值进行流操作
map.values().stream().filter(name -> name.startsWith("张")).filter(name -> name.length() == 3).forEach(name -> System.out.println(name));// 对Map的键进行流操作
map.keySet().stream().filter(name -> name.startsWith("张")).filter(name -> name.length() == 3).forEach(name -> System.out.println(name));// 对Map的键值对进行流操作
map.entrySet().stream().filter(entry -> entry.getValue().startsWith("张")).filter(entry -> entry.getValue().length() == 3).forEach(entry -> System.out.println(entry.getKey()));

4.如何获取数组的Stream流?

String[] names2= {"张翠山“,”东方不败”,”唐大山”,”独孤求败”}Stream< String> s1= Arrays. stream(names2);
Stream< String> s2= Stream. of(names2);|	I
  • Arrays.stream() 是一个静态方法,它接受一个数组作为参数,并返回一个流,该流包含数组中的所有元素。
  • Stream.of() 是一个静态方法,它接受一系列参数,并返回一个包含这些参数的流。

Stream流常见的中间方法

中间方法指的是调用完成后会返回新的Stream流,可以继续使用(支持链式编程)。

在这里插入图片描述

示例:

需求1:找出成绩大于等于60分的数据,并升序后,再输出。

List<Double> scores = new ArrayList<Double>();
Collections.addAll(scores,88.5,100.0,68.0,99.8,9.5);
scores.stream().filter(score -> score > 88.5).forEach(score -> System.out.println(score));//100.0 99.8

需求2,找出年龄大于等于23,且年龄小于等于30岁的学生,并按照年龄降序输出。

List< Student> students = new ArrayList<>();
Student s1= new Student(name: "蜘蛛精", age:26, height:172.5);
Student s2= new Student(name: "蜘蛛精", age:26, height:172.5);
Student s3 = new Student(name: "紫霞", age: 23, height:167.6);
Student s4= new Student(name: "白晶晶", age:25, height:169.0);
Student s5= new Student(name: "牛魔王", age:35, height:183.3);
Student s6= new Student(name: "牛夫人", age:34, height:168.5);
Collections. addAll(students, s1, s2, s3, s4, s5, s6);
//需求2:找出年龄大于等于23,且年龄小于等于30岁的学生,并按照年龄降序输出。
students. stream(). filter(s - > s. getAge() >=23&& s. getAge() <= 30)
. sorted(). forEach(s - > System. out. println(s));

该程序会报错是因为sorted方法不知道该以什么为依据进行排序,

如果我们想要按照年龄进行排序,就需要重载sort方法,用Lambda表达式指定排序的方法。

students. stream(). filter(s - > s. getAge() >=23&& s. getAge() <=30). sorted((o1, o2) - > o2. getAge() - o1. getAge()). forEach(s - > System. out. println(s));

需求3:取出身高最高的前3名学生,并输出。

Double类型不能直接作差,用Double的一个compare方法

students. stream().sorted((o1, o2) - > Double.compare(o2.getHeight(), o1.getHeight())). limit(3). forEach(s - > System. out. println(s));|

需求4:取出身高倒数的2名学生,并输出。

students. stream().sorted((o1, o2) - > Double.compare(o2.getHeight(), o1.getHeight())). skip(students. size() -2). forEach(System. out:: println);

需求5:找出身高超过168的学生叫什么名字,要求去除重复的名字,再输出

students. stream(). filter(s - > s. getHeight() >168). map(Student::getName). distinct(). forEach(System. out:: println);

distinct去重复,自定义类型的对象(希望内容一样就认为重复,重写hashCode, equals)

合并两个流为一个流

Stream< String> st1= Stream. of("张三“,”李四”);
Stream< String> st2= Stream. of("张三2", "李四2", "王五“);
Stream< String> allSt = Stream. concat(st1, st2);
allSt.forEach(System.out::println);

如果两个流的类型不样,那么最后合并的流类型用object。

Stream流常见的终结方法

终结方法指的是调用完成后,不会返回新Stream了,没法继续使用流了。

在这里插入图片描述

示例

List< Student> students = new ArrayList<>();
Student s1= new Student( "蜘蛛精",26,172.5);
Student s2= new Student( "蜘蛛精",26,172.5);
Student s3 = new Student( "紫霞", 23, 167.6);
Student s4= new Student( "白品品", 25,169.0);
Student s5= new Student( "牛魔王",35, 183.3);
Student s6= new Student("牛夫人",34, 168.5);
Collections. addAll(students, s1, s2, s3, s4, s5, s6);

需求1:请计算出身高超过168的学生有几人。

long size = students.stream().filter(higher -> higher.getHeight() > 168).count();
System.out.println(size);//5

需求2:请找出身高最高的学生对象,并输出。

Student s = students.stream().max((o1, o2) -> Double.compare(o1.getHeight(), o2.getHeight())).get();
System.out.println(s);
//Student{name='牛魔王', age=35, height=183.3}

需求3:请找出身高最矮的学生对象,并输出。

Student ss = students.stream().min((o1, o2) -> Double.compare(o1.getHeight(), o2.getHeight())).get();
System.out.println(ss);
//Student{name='紫霞', age=23, height=167.6}

需求4:请找出身高超过170的学生对象,并放到一个新集合中去返回。

流只能收集一次

List< Student> students1= students. stream(). filter(a - > a. getHeight() >170). collect(Collectors. toList());
System. out. println(students1);
Set< Student> students2= students. stream(). filter(a - > a. getHeight() >170). collect(Collectors. toSet());
System. out. println(students2);

需求5:请找出身高超过170的学生对象,并把学生对象的名字和身高,存入到一个Map集合返回。

Map< String, Double> map =students. stream(). filter(a - > a. getHeight() >170). distinct(). collect(Collectors. toMap(a - > a. getName(), a - > a. getHeight()));
System. out. println(map);

总结:

“Stream 不仅是一种 API,更是思维方式的升级——从‘如何做’到‘做什么’。掌握它,你的代码会变得更简洁、更富有表达力。现在就去试试吧!”

相关文章:

告别循环!用Stream优雅处理集合

什么是stream&#xff1f; 也叫Stream流&#xff0c;是jdk8新增的一套API&#xff08;java.util.stream.*&#xff09;可以用于操作集合或者数组的数据。 优势&#xff1a;Stream流大量的结合了Lambda语法的风格编程&#xff0c;提供了一种更加强大&#xff0c;更加简单的方式…...

Linux电源管理、功耗管理 和 发热管理 (CPUFreq、CPUIdle、RPM、thermal、睡眠 和 唤醒)

1 架构图 1.1 Linux内核电源管理的整体架构 《Linux设备驱动开发详解&#xff1a;基于最新的Linux4.0内核》图19.1 1.2 通用的低功耗软件栈 《SoC底层软件低功耗系统设计与实现》 1.3 低功耗系统的架构设计&#xff1b;图1-3 2 系统级睡眠和唤醒管理 Linux系统的待机、睡眠…...

OSCP - Proving Grounds -FunboxEasy

主要知识点 弱密码路径枚举文件上传 具体步骤 首先是nmap扫描一下&#xff0c;虽然只有22&#xff0c;80和3306端口&#xff0c;但是事情没那么简单 Nmap scan report for 192.168.125.111 Host is up (0.45s latency). Not shown: 65532 closed tcp ports (reset) PORT …...

探索 Go 与 Python:性能、适用场景与开发效率对比

1 性能对比&#xff1a;执行速度与资源占用 1.1 Go 的性能优势 Go 语言被设计为具有高效的执行速度和低资源占用。它编译后生成的是机器码&#xff0c;能够直接在硬件上运行&#xff0c;避免了 Python 解释执行的开销。 以下是一个用 Go 实现的简单循环计算代码&#xff1a; …...

c++:构造函数(Constructor)与析构函数(Destructor)

目录 为什么我们需要构造函数&#xff1f; 什么是构造函数&#xff1f; &#x1f9ec; 本质&#xff1a;构造函数是“创建对象的一部分” 为什么 需要析构函数&#xff1f; 什么是析构函数&#xff1f; 析构函数的核心作用 ❗注意点 为什么我们需要构造函数&#xff1f…...

三周年创作纪念日

文章目录 回顾与收获三年收获的五个维度未来的展望致谢与呼唤 亲爱的社区朋友们&#xff0c;大家好&#xff01; 今天是 2025 年 4 月 14 日&#xff0c;距离我在 2022 年 4 月 14 日发布第一篇技术博客《SonarQube 部署》整整 1,095 天。在这条创作之路上&#xff0c;我既感慨…...

Vue 3 国际化实战:支持 Element Plus 组件和语言持久化

目录 Vue 3 国际化实战&#xff1a;支持 Element Plus 组件和语言持久化实现效果&#xff1a;效果一、中英文切换效果二、本地持久化存储效果三、element Plus国际化 vue3项目国际化实现步骤第一步、安装i18n第二步、配置i18n的en和zh第三步&#xff1a;使用 vue-i18n 库来实现…...

1.阿里云快速部署Dify智能应用

一、宝塔面板 宝塔面板是一款功能强大且易于使用的服务器管理软件&#xff0c;支持Linux和Windows系统&#xff0c;通过web端可视化操作&#xff0c;优化了建站流程&#xff0c;提供安全管理、计划任务、文件管理以及软件管理等功能。 1.1 宝塔面板的特点与优势 易用性 宝塔面…...

Ubuntu与windows时间同步

由于ubuntu每次重启后时间老是不对&#xff0c;所以使用ntp服务&#xff0c;让ubuntu作为客户端&#xff0c;去同步windows时间。 一、windows服务端配置 1、启用ntp服务 # 启动W32Time服务&#xff08;若未启动&#xff09; net start w32time # 配置服务为NTP模式 w32tm /…...

在pycharm配置虚拟环境和jupyter,解决jupyter运行失败问题

记录自己pycharm环境配置和解决问题的流程。 解决pycharm无法运行jupyter代码&#xff0c;仅运行import板块显示运行失败&#xff0c;但是控制台不输出任何错误信息&#xff0c;令人困惑。 遇到的问题是&#xff1a;运行代码左下角显示运行失败但是有没有任何的输出错误信息。 …...

Vue 技术解析:从核心概念到实战应用

Vue.js 是一款流行的渐进式前端框架&#xff0c;以其简洁的 API、灵活的组件化结构和高效的响应式数据绑定而受到开发者的广泛欢迎。本文将深入解析 Vue 技术的核心概念、原理和应用场景&#xff0c;帮助开发者更好地理解和使用 Vue.js。 一、Vue 的设计哲学与核心概念 &…...

Series和 DataFrame是 Pandas 库中的两种核心数据结构

Series 和 DataFrame 是 Pandas 库中的两种核心数据结构&#xff0c;它们各有特点和用途。理解它们之间的区别有助于更高效地进行数据分析和处理。以下是 Series 和 DataFrame 的主要区别&#xff1a; 1. 维度 Series&#xff1a;是一维的数组&#xff0c;可以存储任何类型的…...

关于异步消息队列的详细解析,涵盖JMS模式对比、常用组件分析、Spring Boot集成示例及总结

以下是关于异步消息队列的详细解析&#xff0c;涵盖JMS模式对比、常用组件分析、Spring Boot集成示例及总结&#xff1a; 一、异步消息核心概念与JMS模式对比 1. 异步消息核心组件 组件作用生产者发送消息到消息代理&#xff08;如RabbitMQ、Kafka&#xff09;。消息代理中间…...

利用 Python 进行股票数据可视化分析

在金融市场中&#xff0c;股票数据的可视化分析对于投资者和分析师来说至关重要。通过可视化&#xff0c;我们可以更直观地观察股票价格的走势、交易量的变化以及不同股票之间的相关性等。 Python 作为一种功能强大的编程语言&#xff0c;拥有丰富的数据处理和可视化库&#xf…...

【Docker】离线安装Docker

背景 离线安装Docker的必要性&#xff0c;第一&#xff0c;在目前数据安全升级的情况下&#xff0c;很多外网已经基本不好访问了。第二&#xff0c;如果公司有对外部署的需求&#xff0c;那么难免会存在对方只有内网的情况&#xff0c;那么我们就要做到学会离线安装。 下载安…...

kubectl命令补全以及oc命令补全

kubectl命令补全 1.安装bash-completion 如果你用的是Bash(默认情况下是)&#xff0c;先安装补全功能支持包 sudo apt update sudo apt install bash-completion -y2.为kubectl 启用补全功能 会话中临时&#xff1a; source <(kubectl completion bash)持久化配置&#x…...

《 C++ 点滴漫谈: 三十三 》当函数成为参数:解密 C++ 回调函数的全部姿势

一、前言 在现代软件开发中&#xff0c;“解耦” 与 “可扩展性” 已成为衡量一个系统架构优劣的重要标准。而在众多实现解耦机制的技术手段中&#xff0c;“回调函数” 无疑是一种高效且广泛使用的模式。你是否曾经在编写排序算法时&#xff0c;希望允许用户自定义排序规则&a…...

极简cnn-based手写数字识别程序

1.先看看识别效果&#xff1a; 这个程序识别的是0~9的一组手写数字&#xff0c;这是最终的识别效果&#xff0c;为1&#xff0c;代表识别成功&#xff0c;0为失败。 然后数据源是&#xff1a;ds deeplake.load(hub://activeloop/optical-handwritten-digits-train)里面是一组…...

C++核心机制-this 指针传递与内存布局分析

示例代码 #include<iostream> using namespace std;class A { public:int a;A() {printf("A:A()的this指针&#xff1a;%p!\n", this);}void funcA() {printf("A:funcA()的this指针&#xff1a;%p!\n", this);} };class B { public:int b;B() {prin…...

vue3 history路由模式刷新页面报错问题解决

在使用history路由模式时刷新网页提示404错误&#xff0c;这是改怎么办呢。 官方解决办法 https://router.vuejs.org/zh/guide/essentials/history-mode.html...

PHP爬虫教程:使用cURL和Simple HTML DOM Parser

一个关于如何使用PHP的cURL和HTML解析器来创建爬虫的教程&#xff0c;特别是处理代理信息的部分。首先&#xff0c;我需要确定用户的需求是什么。可能他们想从某个网站抓取数据&#xff0c;但遇到了反爬措施&#xff0c;需要使用代理来避免被封IP。不过用户没有提到具体的目标网…...

Web前端开发——格式化文本与段落(上)

一、学习目标 网页内容的排版包括文本格式化、段落格式化和整个页面的格式化&#xff0c;这是设计个网页的基础。文本格式化标记分为字体标记、文字修饰标记。字体标记和文字修饰标记包括对于字体样式的一些特殊修改。段落格式化标记分为段落标记、换行记、水平分隔线标记等。…...

技术方案选型要考虑哪些点?

在概要设计阶段&#xff0c;技术方案选型是核心环节之一&#xff0c;需综合考虑系统需求、技术可行性、团队能力及长期维护成本。以下是技术方案选型需包含的核心内容及设计要点&#xff0c;结合行业实践和搜索结果中的方法论&#xff1a; 理论 一、系统架构选型 整体架构模式…...

前端工程化之自动化构建

自动化构建 自动化构建的基本知识历史云构建 和 自动化构建 的区别&#xff1a;部署环境&#xff1a;构建&#xff1a;构建产物构建和打包的性能优化页面加载优化构建速度优化 DevOps原则反馈的技术实践 encode-bundlepackage.json解读src/cli-default.tssrc/cli-node.tssrc/cl…...

3.2.2.1 Spring Boot配置静态资源映射

在Spring Boot中配置静态资源映射&#xff0c;可以通过默认路径或自定义配置实现。默认情况下&#xff0c;Spring Boot会在classpath:/static/等目录下查找静态资源。若需自定义映射&#xff0c;可通过实现WebMvcConfigurer接口的addResourceHandlers方法或在全局配置文件中设置…...

# 更换手机热点后secureCRT无法连接centOS7系统

更换手机热点后secureCRT无法连接centOS7系统 一、问题描述 某些情况下&#xff0c;我们可能使用手机共享热点而给电脑联网。本来用一个手机热点共享网络时&#xff0c;SecureCRT可以正常连接到CentOS 7虚拟机&#xff0c;当更换一个手机热点时&#xff0c;突然发现SecureCR…...

【高性能缓存Redis_中间件】三、redis 精通:性能优化与生产实践

一、引言​ 在前两篇 Redis 消息队列的文章中&#xff0c;我们掌握了基础使用和高级特性。本文作为系列终篇&#xff0c;将聚焦生产环境的性能优化与全流程实践&#xff0c;请各位跟随小编的步伐一起构建高可靠、高性能的消息处理系统&#xff08;文章中的演示均为Centos7的背…...

jupyter notebook 无法启动- markupsafe导致

一、运行jupyter notebook和Spyder报错&#xff1a;(已安装了Anaconda&#xff0c;以前可打开) 1.背景&#xff1a;为了部署机器学习模型&#xff0c;按教程直接安装了flask 和markupsafe&#xff0c;导致jupyter notebook&#xff0c;Spyder 打不开。 pip install flas…...

Kotlin作用域函数

在 Kotlin 中&#xff0c;.apply 是一个 作用域函数&#xff08;Scope Function&#xff09;&#xff0c;它允许你在一个对象的上下文中执行代码块&#xff0c;并返回该对象本身。它的设计目的是为了 对象初始化 或 链式调用 时保持代码的简洁性和可读性。 // 不使用 apply va…...

设计模式:工厂方法模式 - 高扩展性与低耦合的设计之道

一、为什么需要工厂方法模式&#xff1f; 在软件开发中&#xff0c;对象创建与使用耦合会影响系统的灵活性和扩展性。以通知系统&#xff08;支持邮件通知、短信通知和推送通知&#xff09;为例 &#xff1a;直接实例化。 Notification email new EmailNotification(); Noti…...