【Java面试系列】JDK 1.8 新特性之 Stream API

在这里插入图片描述

目录

  • 一、Stream 简介
  • 二、Stream 特点:
    • Stream 注意点:
    • 1、什么是聚合操作
    • 2、Stream 流
      • 1、什么是流
      • 2、流的构成
      • 3、stream 流的两种操作
      • 4、惰性求值和及早求值方法
      • 5、Stream 流的并行
  • 三、Stream操作的三个步骤
    • 1、创建流
      • 第一种:通过集合
      • 第二种:通过数组
      • 第三种:Stream.of()静态方法直接手动生成一个Stream
      • 第四种:创建无限流
      • 第五种:自己构建
    • 2、中间操作
    • 3、终止操作:一个终止操作,执行中间操作连,产生结果。
  • 系列文章
  • 版本记录

在这里插入图片描述


一、Stream 简介

Java 8 引入了全新的 Stream API,这里的 Stream 和 I/O 流不同,它更像具有 Iterable 的集合类,但行为和集合类又有所不同。
Stream 是 Java 8 的新特性,是对容器对象功能的增强,它专注于对容器对象进行各种非常便利、高效的聚合操作(aggregate operation)或者大批量数据操作。
Stream 是用函数式编程方式在集合类上进行复杂操作的工具,开发者可以更容易地使用 Lambda 表达式,并且更方便地实现对集合的查找、遍历、过滤以及常见计算等。
同时,它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。
所以说,Java 8 中首次出现的 java.util.stream 是一个函数式语言+多核时代综合影响的产物。

二、Stream 特点:

(1)Stream 流是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列;
(2)Stream 相当于高级版的 Iterator;
(3)Stream 的聚合操作与数据库 SQL 的聚合操作 sorted、filter、map 等非常类似;
(4)Stream 是对容器对象功能的增强,它专注于对容器对象进行各种非常便利、高效的 聚合操作(aggregate operation)或者大批量数据操作;
(5)Stream 是用函数式编程方式在集合类上进行复杂操作的工具,其集成了Java 8中的众多新特性之一的聚合操作,开发者可以更容易地使用Lambda表达式,并且更方便地实现对集合的查找、遍历、过滤以及常见计算等;
(6)在数据操作方面,Stream 不仅可以通过串行的方式实现数据操作,还可以通过并行的方式处理大批量数据,提高处理效率;

Stream 注意点:

(1)Stream 不会自己存储数据。
(2)Stream 不会改变原对象,他们会返回一个新的 Stream。
(3)Stream 操作是延迟的,他们会等到需要的结果时才执行。
(4)用并行流并不一定会提高效率,因为 jvm 对数据进行切片和切换线程也是需要时间的。

1、什么是聚合操作

在传统的 J2EE 应用中,Java 代码就必须依赖于关系型数据库的聚合操作来完成诸如客户每月平均消费金额、最昂贵的在售商品、本周完成的有效订单(排除了无效的)以及取十个数据样本作为首页推荐等需求。但在当今这个数据大爆炸的时代,在数据来源多样化、数据海量化的今天,很多时候不得不脱离 RDBMS,或者以底层返回的数据为基础进行更上层的数据统计。
而 Java 的集合 API 中,仅仅有极少量的辅助型方法,更多的时候是程序员需要用 Iterator 来遍历集合,完成相关的聚合应用逻辑,这是一种远不够高效、笨拙的方法。而在 Java 8 使用 Stream,代码更加简洁易读;而且使用并发模式,程序执行速度更快。

2、Stream 流

1、什么是流

1、Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如,“过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母”等,Stream 会隐式地在内部进行遍历,做出相应的数据转换。Stream 就如同一个迭代器(Iterator),单向不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返。

2、而和迭代器又不同的是,Stream 可以并行化操作,迭代器只能命令式地、串行化操作。顾名思义,当使用串行方式去遍历时,每个 item 读完后再读下一个 item。而使用并行去遍历时,数据会被分片成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出。Stream 的并行操作依赖于 Java 7 中引入的 Fork/Join 框架(JSR166y)来拆分任务和加速处理过程。

3、Stream 的另外一大特点是,数据源本身可以是无限的。

2、流的构成

当我们使用一个流的时候,通常包括三个基本步骤:获取数据源(source)→ 数据转换 → 执行操作获取想要的结果。如下图所示:
在这里插入图片描述

3、stream 流的两种操作

每次数据转换都保持原有 Stream 对象不改变,返回一个新的 Stream 对象(可以有多次转换),这就允许对其操作可以像链条一样排列,变成一个管道,如:
在这里插入图片描述

图中所示,整个过程就是将 goods 元素集合作为一个 “序列”,进行一组 “流水线” 操作: goods 集合提供了元素序列的数据源;通过 stream() 方法获得 Stream,filter / sorted / limit 是一组链式数据处理,连接起来”构成 “流水线”;forEach 最终执行。

1、filter/sorted/limit 的返回值均为 Stream(类似于 Builder 模式),但它们并不立即执行,而是构成了 “流水线”,直到 forEach 最终执行,并且关闭 Stream。 因此将 filter/sorted/limited 等能够 “连接起来”,并且返回 Stream 的方法称为 “中间操作”(Intermediate);将 forEach 等最终执行,并且关闭 Stream 的方法称为 “终止操作”(Terminal)。

2、intermediate 操作目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。一个流只能有一个 terminal 操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以这必定是流的最后一个操作。Terminal 操作的执行,才会真正开始流的遍历,并且会生成一个结果。

3、Stream 的中间操作并不是立即执行,而是 “延迟的”、“按需计算”;完成 “终止操作” 后,Stream 将被关闭。多个中间操作可以连接起来性格一条流水线,除非流水线上触发器终止操作,否则中间操作不会执行任何的处理,而是在终止操作时一次性全部处理,成为惰性求值。

4、惰性求值和及早求值方法

1、像 filter 这样只描述Stream,最终不产生新集合的方法叫作惰性求值方法;而像 count 这样最终会从 Stream 产生值的方法叫作及早求值方法。
如何判断一个操作是惰性求值还是及早求值:
只需要看其返回值即可:如果返回值是Stream,那么就是惰性求值;如果返回值不是 Stream 或者是 void,那么就是及早求值。

2、在一个 Stream 操作中,可以有多次惰性求值,但有且仅有一次及早求值。

3、中间操作是 lazy(惰性求值) 的,只有在终止操作执行时,才会一次性执行。可以这么认为,Stream 里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中,在终止操作的时候循环 Stream 对应的集合,然后对每个元素执行所有的函数。

5、Stream 流的并行

并行处理指的是 Stream 结合了 ForkJoin 框架,对 Stream 处理进行了分片,Spliterator.estimateSize 会估算出分片的数据量;
通过预估的数据量获取最小处理单元的阈值,如果当前分片大小大于最小处理单元的阈值,就继续切分集合;
每个分片都将会生成一个 Sink 链表,当所有分片操作完成后,ForkJoin 框架将会合并所有分片结果集。

三、Stream操作的三个步骤

  • 1、创建Stream:一个数据源(例如:set 、list),获取一个流

  • 2、中间操作:一个中间操作连接,对数据源的数据进行处理

  • 3、终止操作:一个终止操作,执行中间操作连,产生结果。

1、创建流

创建流方式有多种:

第一种:通过集合

对于Collection接口(List 、Set、Queue等)直接调用Stream()方法可以获取Stream

List<String> list = new ArrayList<>();
Stream<String> stringStream = list.stream(); //返回一个顺序流
Stream<String> parallelStream = list.parallelStream(); //返回一个并行流(可多线程)

第二种:通过数组

把数组变成Stream使用Arrays.stream()方法

Stream<String> stream1 = Arrays.stream(new String[]{"CBB", "YJJ", "CB", "CJJ"});

第三种:Stream.of()静态方法直接手动生成一个Stream

    Stream<String> stream = Stream.of("A", "B", "C", "D");

第四种:创建无限流

        //迭代//遍历10个奇数Stream.iterate(1,t->t+2).limit(10).forEach(System.out::println);//生成//生成10个随机数Stream.generate(Math::random).limit(10).forEach(System.out::println);

第五种:自己构建

2、中间操作

一个流可以后面跟随着0个或者多个中间操作,其目的是打开流,做出某种程度的数据过滤、去重、排序、映射、跳过等。然后返回一个新的流,交给下一个使用,仅仅是调用这个方法,没有真正开始遍历。

map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered

3、终止操作:一个终止操作,执行中间操作连,产生结果。

forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

package com.chen.test.JAVA8Features.Stream;import java.util.*;
import java.util.stream.Collectors;public class StreamDemo01 {public static void main(String[] args) {List<Integer> list = new ArrayList<>();for (int i = 0; i < 10; i++) {list.add(i);}//mapList<Integer> collect = list.stream().map(n -> n * 2).collect(Collectors.toCollection(ArrayList::new));collect.forEach(System.out::println);//filer 过滤List<Integer> list1 = list.stream().filter(n -> n % 2 == 0).collect(Collectors.toList());list1.forEach(System.out::println);//distinct 去重List<Integer> list2 = list.stream().distinct().collect(Collectors.toList());list2.forEach(System.out::println);//skip 跳过List<Integer> list3 = list.stream().skip(3).collect(Collectors.toList());list3.forEach(System.out::println);//limit 截取Set<Integer> set = list.stream().limit(3).collect(Collectors.toSet());set.forEach(System.out::println);//skip  and limit 组合使用List<Integer> list4 = list.stream().skip(3).limit(5).collect(Collectors.toList());list4.forEach(System.out::println);}
}

————————————————

                        版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/weixin_40294256/article/details/126338618

系列文章


内容地址 链接
JAVA面试常见问题
JAVA面试Spring知识点
JAVA面试Mysql
JAVA面试Redis常见问题
JAVA面试MongoDB
JAVA面试JDK 1.8 新特性之 Lambda表达式
JAVA介绍Linux (实战)常用命令
=========================================================================
👊如果你对该系列文章有兴趣的话,欢迎持续关注博主动态,博主会持续输出优质内容👊

👊 博主很需要大家的支持,你的支持是我创作的不竭动力👊

👊 ~ 点赞收藏+关注 ~👊
=========================================================================

版本记录


  • 2023-10-18 第一版

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

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

相关文章

网络原理 - HTTP/HTTPS(4)

HTTP响应详解 认识"状态码"(status code) 状态码表示访问一个页面的结果.(是访问成功,还是失败,还是其它的一些情况...).(响应结果如何) 学习状态码 -> 为了调试问题. 写服务器时,按照状态码的含义正确使用. 200 OK 这是最常见的状态码,表示访问成功. 抓包抓…

Unity3d Mesh篇(一)— 创建简单三角面

文章目录 前言一、Mesh组成二、使用步骤三、效果四、总结 前言 Mesh&#xff08;网格&#xff09;是一种常用的3D图形表示方法&#xff0c;它由顶点&#xff0c;法线&#xff0c;UV 坐标&#xff0c;和三角形等组成。您可以使用 Mesh 类的方法来创建或修改网格&#xff0c;也可…

ARMv8-AArch64 的异常处理模型详解之异常处理详解(进入异常以及异常路由)

在上篇文章 ARMv8-AArch64 的异常处理模型详解之异常处理概述Handling exceptions中&#xff0c;作者对异常处理整体流程以及相关概念做了梳理。接下来&#xff0c;本文将详细介绍处理器在获取异常、异常处理以及异常返回等过程中都做了哪些工作。 ARMv8-AArch64 的异常处理模型…

单片机学习笔记---红外遥控(外部中断)

目录 红外遥控简介 硬件电路 基本发送与接收 NEC编码​​​​​​​ 遥控器键码 复习外部中断和定时器 红外遥控简介 红外遥控是利用红外光进行通信的设备&#xff0c;由红外LED将调制后的信号发出&#xff0c;由专用的红外接收头进行解调输出 通信方式&#xff1a;单工…

消息中间件-面试题

MQ选择 一、Kafka 1、消息队列如何保证消息可靠性 消息不重复 生产者控制消费者幂等消息不丢失 生产者发送,要确认broker收到并持久化broker确认消费者消费完,再删除消息2、kafka是什么 Kafka是一种高吞吐量、分布式、基于发布/订阅的消息中间件,是Apache的开源项目。broke…

web组态软件

1、强大的画面显示web组态功能 2、良好的开放性。 开放性是指组态软件能与多种通信协议互联&#xff0c;支持多种硬件设备&#xff0c;向上能与管理层通信&#xff0c;实现上位机和下位机的双向通信。 3、丰富的功能模块。 web组态提供丰富的控制功能库&#xff0c;满足用户的测…

MySQL安装教程(详细版)

今天分享的是Win10系统下MySQL的安装教程&#xff0c;打开MySQL官网&#xff0c;按步骤走呀~ 宝们安装MySQL后&#xff0c;需要简单回顾一下关系型数据库的介绍与历史&#xff08;History of DataBase&#xff09; 和 常见关系型数据库产品介绍 呀&#xff0c;后面就会进入正式…

JVM常见问题笔记分享

文章目录 1 JVM组成1.1 JVM由那些部分组成&#xff0c;运行流程是什么&#xff1f;1.2 什么是程序计数器&#xff1f;1.3 你能给我详细的介绍Java堆吗?元空间(MetaSpace)介绍 1.4 什么是虚拟机栈1.5 堆和栈的区别1.6 能不能解释一下方法区&#xff1f;1.5.1 概述1.5.2 常量池1…

【实习】深信服防火墙网络安全生产实习

一、实习概况 1.1实习目的 1.掌握防火墙规则的作用2.掌握代理上网功能的作用3.掌握端口映射功能的作用 1.2实习任务 1.防火墙的WEB控制台 2.需要在防火墙上配置dnat …

Java 后端面试指南

面试指南 TMD&#xff0c;一个后端为什么要了解那么多的知识&#xff0c;真是服了。啥啥都得了解 MySQL MySQL索引可能在以下几种情况下失效&#xff1a; 不遵循最左匹配原则&#xff1a;在联合索引中&#xff0c;如果没有使用索引的最左前缀&#xff0c;即查询条件中没有包含…

使用Docker部署Docker-Compose-Ui工具并实现公网访问

文章目录 1. 安装Docker2. 检查本地docker环境3. 安装cpolar内网穿透4. 使用固定二级子域名地址远程访问 Docker Compose UI是Docker Compose的web界面。这个项目的目标是在Docker Compose之上提供一个最小的HTTP API&#xff0c;同时保持与Docker Compose CLI的完全互操作性。…

pandas/geopandas 笔记:判断地点在不在路网上 不在路网的点和路网的距离

0 导入库 import osimport pandas as pd pd.set_option(display.max_rows,5)import osmnx as oximport geopandas as gpd from shapely.geometry import Point 1 读取数据 假设我们有 如下的数据&#xff1a; 1.1 新加坡室外基站位置数据 cell_stationpd.read_csv(outdoor…

相机图像质量研究(40)常见问题总结:显示器对成像的影响--画面泛白

系列文章目录 相机图像质量研究(1)Camera成像流程介绍 相机图像质量研究(2)ISP专用平台调优介绍 相机图像质量研究(3)图像质量测试介绍 相机图像质量研究(4)常见问题总结&#xff1a;光学结构对成像的影响--焦距 相机图像质量研究(5)常见问题总结&#xff1a;光学结构对成…

2024牛客寒假算法基础集训营4

D.守恒 阿宁有一个长度为 n 正整数数组 a。 可以进行任意次操作&#xff0c;每次操作选择数组 a 的两个元素&#xff0c;其中一个加 1&#xff0c;另一个减 1&#xff0c;要求每次操作后 a 的各元素仍然是正整数。 阿宁想知道操作结束后&#xff0c;数组的最大公约数可能有多少…

基于微信小程序的比赛赛程管理系统设计与实现

在全面健身的倡导下通过各级赛事的举办完成体育人才的选拔&#xff0c;当由于缺乏信息化的管理手段而只能通过人工完成比赛报名、赛程制定及成绩记录等流程的管理&#xff0c;因此常常因意外而导致比赛赛程管理不善、成绩不理想等问题出现。为了帮助比赛组织者优化赛程管理流程…

Java 那些诗一般的 数据类型 (1)

本篇会加入个人的所谓‘鱼式疯言’ ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. &#x1f92d;&#x1f92d;&#x1f92d;可能说的不是那么严谨.但小编初心是能让更多人…

善于利用GPT确实可以解决许多难题

当我设计一个导出Word文档的功能时&#xff0c;我面临了一个挑战。在技术选型时&#xff0c;我选择了poi-tl这个模板引擎&#xff0c;因为在网上看到了很多关于它的推荐。poi-tl可以根据模板快速导出Word文档。虽然之前没有做过类似的功能&#xff0c;而且项目中也没有用过&…

基于Python的热点分析预警系统

项目&#xff1a;基于Python的热点分析预警系统 摘 要 基于网络爬虫的数据可视化服务系统是一种能自动从网络上收集信息的工具&#xff0c;可根据用户的需求定向采集特定数据信息的工具&#xff0c;本项目通过研究爬取微博网来实现微博热点分析数据信息可视化系统功能。对于采…

顺序表详解(SeqList)

本文使用C语言进行顺序表的代码实现。 博主将使用代码和相关知识相结合的方式进行讲解&#xff0c;简单易懂&#xff0c;懵懂的大学生一听就会~ 顺序表是一种线性表的存储结构&#xff0c;它将数据元素存储在一段连续的存储空间中&#xff0c;每个元素占据一个存储单元&#x…

Java入门-可重入锁

可重入锁 什么是可重入锁? 当线程获取某个锁后&#xff0c;还可以继续获取它&#xff0c;可以递归调用&#xff0c;而不会发生死锁&#xff1b; 可重入锁案例 程序可重入加锁 A.class,没有发生死锁。 sychronized锁 package com.wnhz.lock.reentrant;public class Sychroniz…