返回顶部
首页 > 资讯 > 后端开发 > JAVA >java Stream编程笔记
  • 541
分享到

java Stream编程笔记

java笔记开发语言后端 2023-12-25 13:12:27 541人浏览 薄情痞子
摘要

文章目录 Stream介绍什么是 Stream? Stream中间操作过滤操作(filter)映射操作(map)排序操作(sorted)截断操作(limit 和 skip) Stream 的终止操作forEach 和 p

Stream

介绍

Java Stream 的主要作用有以下几个方面:

  • 简化集合操作:使用传统的 for 循环或迭代器来处理集合数据可能会导致冗长而复杂的代码。
  • 延迟计算:流式操作允许你在处理数据之前定义一系列的操作步骤,但只在需要结果时才会实际执行。这种延迟计算的特性意味着可以根据需要动态调整数据处理的操作流程,提升效率。
  • 并行处理:Java Stream 提供了并行流的支持,可以将数据分成多个块进行并行处理,从而充分利用多核处理器的性能优势,提高代码的执行速度。
  • 函数式编程风格:流式编程鼓励使用函数式编程的思想,通过传递函数作为参数或使用 Lambda 表达式来实现代码的简化和灵活性。

为什么使用流式编程可以提高代码可读性和简洁性

  • 声明式编程风格:流式编程采用了一种声明式的编程风格,你只需描述你想要对数据执行的操作,而不需要显式地编写迭代和控制流语句。

  • 链式调用:流式编程使用方法链式调用的方式,将多个操作链接在一起。每个方法都返回一个新的流对象,这样你可以像“流水线”一样在代码中顺序地写下各种操作,使代码逻辑清晰明了。

  • 操作的组合:流式编程提供了一系列的操作方法,如过滤、映射、排序、聚合等,这些方法可以按照需要进行组合使用。你可以根据具体的业务需求将这些操作串联起来,形成一个复杂的处理流程,而不需要编写大量的循环和条件语句。

  • 减少中间状态:传统的迭代方式通常需要引入中间变量来保存中间结果,这样会增加代码的复杂度和维护成本。而流式编程将多个操作链接在一起,通过流对象本身来传递数据,避免了中间状态的引入。

  • 减少循环和条件:流式编程可以替代传统的循环和条件语句的使用。

什么是 Stream?

Stream(流)是一个来自数据源的元素队列并支持聚合操作

  • 元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
  • 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
  • 聚合操作 类似sql语句一样的操作, 比如filter, map, reduce, find, match, sorted等。
  • 不可变性:Stream 是不可变的,它不会修改原始数据源,也不会产生中间状态或副作用。每个操作都会返回一个新的流对象,以保证数据的不可变性。
    和以前的Collection操作不同, Stream操作还有两个基础的特征:
  • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
  • 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

Stream中的操作大体可以分为两类

  • 中间操作:将流一层层的进行处理,并向下一层进行传递,如 filter map sorted等。
    中间操作又分为有状态(stateful)及无状态(stateless)
    • 有状态:必须等上一步操作完拿到全部元素后才可操作,如sorted
    • 无状态:该操作的数据不收上一步操作的影响,如filter map
  • 终止操作:触发数据的流动,并收集结果,如collect findFirst forEach等。终止操作又分为短路操作(short-circuiting)及非短路操作(non-short-circuiting)
    • 短路操作:会在适当的时刻终止遍历,类似于break,如anyMatch findFirst等
    • 非短路操作:会遍历所有元素,如collect max等

Stream中间操作

过滤操作(filter)

过滤操作(filter),它接受一个 Predicate 函数作为参数,用于过滤 Stream 中的元素。只有满足 Predicate 条件的元素会被保留下来,而不满足条件的元素将被过滤掉。

过滤操作的语法如下

Stream<T> filter(Predicate<? super T> predicate)

其中,T 表示 Stream 元素的类型,predicate 是一个函数式接口 Predicate 的实例,它的泛型参数和 Stream 元素类型一致,并且predicate返回的值必须是boolean类型,因为需要通过真假值判断是否要过滤该值。

使用过滤操作可以根据自定义的条件来筛选出符合要求的元素,从而对 Stream 进行精确的数据过滤。

下面是一个示例,演示如何使用过滤操作筛选出一个整数流中的大于三的数:

        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);//        生成流式对象//        Stream stream = numbers.stream();        List<Integer> list=numbers.stream().filter(                (x)->{return x>3;}  //lambda表达式 可简化成下面的写法//                x->x>3        ).toList();        System.out.println("number中大于3的数: "+list.toString());

映射操作(map)

映射操作(map),它接受一个 Function 函数作为参数,用于对 Stream 中的每个元素进行映射转换,生成一个新的 Stream。

映射操作的语法如下:

<R> Stream<R> map(Function<? super T, ? extends R> mapper)

其中,T 表示原始 Stream 的元素类型,R 表示映射后的 Stream 的元素类型,mapper 是一个函数式接口 Function 的实例,可以进行不同的映射操作.

下面是一个示例,演示如何使用映射操作将一个字符串流中的每个字符串转换为其长度:

        List<String> numbers = Arrays.asList("apple", "banana", "cherry");//        生成流式对象//        Stream stream = numbers.stream();        numbers.stream().map(                String::length        ).forEach(System.out::println);

在这个示例中,我们首先创建了一个包含字符串的 Stream,并调用 map() 方法传入String::length,表示要将每个字符串转换为其长度。然后通过 forEach() 方法遍历输出结果。

注意: 映射操作可能引发空指针异常(NullPointerException),因此在执行映射操作时,应确保原始 Stream 中不包含空值,并根据具体情况进行空值处理。

排序操作(sorted)

排序操作(sorted)是 Stream api 中的一种常用操作方法,它用于对 Stream 中的元素进行排序。排序操作可以按照自然顺序或者使用自定义的比较器进行排序。

排序操作的语法如下:

Stream<T> sorted() Stream<T> sorted(Comparator<? super T> comparator)
  • 第一种语法形式中,sorted() 方法会根据元素的自然顺序进行排序。如果元素实现了 Comparable 接口并且具备自然顺序,那么可以直接调用该方法进行排序。

  • 第二种语法形式中,sorted(Comparator comparator) 方法接受一个比较器(Comparator)作为参数,用于指定元素的排序规则。通过自定义比较器,可以对非 Comparable 类型的对象进行排序。

下面是一个示例,演示如何使用排序操作对一个字符串流进行排序:

        List<String> numbers = Arrays.asList("apple", "banana", "cherry");//        生成流式对象//        Stream stream = numbers.stream();        numbers.stream().sorted().forEach(System.out::println);

输出

applebananacherry

注意: 排序操作可能会影响程序的性能,特别是对于大型数据流或者复杂的排序规则。因此,在实际应用中,需要根据具体情况进行权衡和优化,选择合适的算法数据结构来提高排序的效率。

截断操作(limit 和 skip)

截断操作(limit和skip),用于在处理流的过程中对元素进行截断。

  1. limit(n):保留流中的前n个元素,返回一个包含最多n个元素的新流。如果流中元素少于n个,则返回原始流。
  2. skip(n):跳过流中的前n个元素,返回一个包含剩余元素的新流。如果流中元素少于n个,则返回一个空流。
    下面分别详细介绍这两个方法的使用。

注意: 在使用截断操作时需要注意流的有界性。如果流是无界的(例如 Stream.generate()),那么使用 limit() 方法可能导致程序陷入无限循环,而使用 skip() 方法则没有意义。

Stream 的终止操作

forEach 和 peek

forEach和peek都是Stream API中用于遍历流中元素的操作方法,它们在处理流的过程中提供了不同的功能和使用场景。

forEach: forEach是一个终端操作方法,它接受一个Consumer函数作为参数,对流中的每个元素执行该函数。forEach会遍历整个流,对每个元素执行相同的操作。

示例代码:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");names.stream()     .forEach(System.out::println);

peek: peek是一个中间操作方法,它接受一个Consumer函数作为参数,对流中的每个元素执行该函数。与forEach不同的是,peek方法会返回一个新的流,该流中的元素和原始流中的元素相同。

示例代码:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");List<String> upperCaseNames = names.stream()       .map(String::toUpperCase)       .peek(System.out::println)       .toList();

聚合操作(reduce)

reduce和collect都是Stream API中用于聚合操作的方法,它们可以将流中的元素进行汇总、计算和收集。

reduce: reduce是一个终端操作方法,它接受一个BinaryOperator函数作为参数,对流中的元素逐个进行合并操作,最终得到一个结果。该方法会将流中的第一个元素作为初始值,然后将初始值与下一个元素传递给BinaryOperator函数进行计算,得到的结果再与下一个元素进行计算,以此类推,直到遍历完所有元素。

示例代码:

        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);        numbers.stream().reduce(Integer::sum).ifPresent(System.out::println);//输出结果15

在这个示例中,我们创建了一个包含整数的List,并通过stream()方法将其转换为流。然后使用reduce方法对流中的元素进行求和操作,将每个元素依次相加,得到结果15。

匹配操作(allMatch、anyMatch 和 noneMatch)

在 Stream API 中,allMatch、anyMatch 和 noneMatch 是用于进行匹配操作的方法,它们可以用来检查流中的元素是否满足特定的条件。

allMatch: allMatch 方法用于判断流中的所有元素是否都满足给定的条件。当流中的所有元素都满足条件时,返回 true;如果存在一个元素不满足条件,则返回 false。

anyMatch: anyMatch 方法用于判断流中是否存在至少一个元素满足给定的条件。当流中至少有一个元素满足条件时,返回 true;如果没有元素满足条件,则返回 false。

在这个示例中,我们创建了一个包含整数的 List,并通过 stream() 方法将其转换为流。然后使用 anyMatch 方法判断流中是否存在偶数。由于列表中存在偶数,所以返回 true。

noneMatch: noneMatch 方法用于判断流中的所有元素是否都不满足给定的条件。当流中没有元素满足条件时,返回 true;如果存在一个元素满足条件,则返回 false。

示例代码:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);boolean allEven = numbers.stream()                         .allMatch(n -> n % 2 == 0);System.out.println(allEven); // 输出结果: falseboolean hasEven = numbers.stream()                         .anyMatch(n -> n % 2 == 0);System.out.println(hasEven); // 输出结果: trueboolean noneNegative = numbers.stream() .noneMatch(n -> n < 0);System.out.println(noneNegative); // 输出结果: true

查找操作(findFirst 和 findAny)

在 Stream API 中,findFirst 和 findAny 是用于查找操作的方法,它们可以用来从流中获取满足特定条件的元素。

findFirst: findFirst 方法用于返回流中的第一个元素。它返回一个 Optional 对象,如果流为空,则返回一个空的 Optional;如果流非空,则返回流中的第一个元素的 Optional。

findAny: findAny 方法用于返回流中的任意一个元素。它返回一个 Optional 对象,如果流为空,则返回一个空的 Optional;如果流非空,则返回流中的任意一个元素的 Optional。在顺序流中,通常会返回第一个元素;而在并行流中,由于多线程的处理,可能返回不同的元素。

示例代码

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");Optional<String> first = names.stream()  .findFirst();first.ifPresent(System.out::println); // 输出结果: AliceList<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);Optional<Integer> any = numbers.stream()   .filter(n -> n % 2 == 0)   .findAny();any.ifPresent(System.out::println); // 输出结果: 2 或 4(取决于并行处理的结果)

统计操作(count、max 和 min)

在 Stream API 中,count、max 和 min 是用于统计操作的方法,它们可以用来获取流中元素的数量、最大值和最小值。

count: count 方法用于返回流中元素的数量。它返回一个 long 类型的值,表示流中的元素个数。

max: max 方法用于返回流中的最大值。

min: min 方法用于返回流中的最小值。它返回一个 Optional 对象,如果流为空,则返回一个空的 Optional;如果流非空,则返回流中的最小值的 Optional。

示例代码

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);long count = numbers.stream()                    .count();System.out.println(count); // 输出结果: 5Optional<Integer> max = numbers.stream()   .max(Integer::compareTo);max.ifPresent(System.out::println); // 输出结果: 5Optional<Integer> min = numbers.stream()   .min(Integer::compareTo);min.ifPresent(System.out::println); // 输出结果: 1

来源地址:https://blog.csdn.net/studycodeday/article/details/134359740

--结束END--

本文标题: java Stream编程笔记

本文链接: https://lsjlt.com/news/551779.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • java Stream编程笔记
    文章目录 Stream介绍什么是 Stream? Stream中间操作过滤操作(filter)映射操作(map)排序操作(sorted)截断操作(limit 和 skip) Stream 的终止操作forEach 和 p...
    99+
    2023-12-25
    java 笔记 开发语言 后端
  • JAVA编程学习笔记
    常用代码、特定函数、复杂概念、特定功能……在学习编程的过程中你会记录下哪些内容?快来分享你的笔记,一起切磋进步吧! 一、常用代码 在java编程中常用需要储备的就是工具类。包括封装的时间工具类。htt...
    99+
    2023-09-03
    java 学习 笔记
  • JAVA编程思想笔记 : 复用类
    复用代码是 Java 众多引人注目的功能之一.但是想要成为机具革命性的语言,仅仅能复制代码并对之加以改变是不够的,它还必须能够做更多的事情.组合语法只需将对象引用置于新类中即可.初始化引用位置定义对象的地方,他们总是能够在构造器被调用之前初...
    99+
    2021-03-31
    java教程 JAVA
  • protobuf c++编程笔记
    目录字段内容的定义修饰符字段类型引用方式不同字段的方法1)optional修饰的基本类型:2)optional修饰的对象类型:3)repeated修饰的基本类型:4)repeated...
    99+
    2024-04-02
  • Java官方笔记之编写运行Java程序
    你可能已经迫不及待想安装Java,写个Java程序跑起来了。但是在这之前,有些概念需要提前了解,因为Java跟C、C++和Python都有点不一样。编译和执行​我们在文本文件中编写英文代码,这些英文计算机是看不懂的,因此需要做一下转换,转换...
    99+
    2023-05-14
    Java javac 命令
  • Nodejs学习笔记之Stream模块
    一,开篇分析 流是一个抽象接口,被 Node 中的很多对象所实现。比如对一个 HTTP 服务器的请求是一个流,stdout 也是一个流。流是可读,可写或兼具两者的。 最早接触Stream是从早期的unix开...
    99+
    2022-06-04
    学习笔记 模块 Nodejs
  • Java Socket编程笔记_动力节点Java学院整理
    对于即时类应用或者即时类的游戏,HTTP协议很多时候无法满足于我们的需求。这会,Socket对于我们来说就非常实用了。下面是本次学习的笔记。主要分异常类型、交互原理、Socket、ServerSocket、多线程这几个方面阐述。异常类型在了...
    99+
    2023-05-31
    java socket 编程
  • 学习异步编程:Java和JavaScript笔记对比
    异步编程是现代编程语言中的重要概念,它可以让程序在执行长时间的操作时不会被阻塞。Java和JavaScript都是广泛使用的编程语言,它们都支持异步编程。本文将比较Java和JavaScript中异步编程的不同方法,并提供一些示例代码来帮...
    99+
    2023-09-10
    javascript 学习笔记 异步编程
  • Java编程思想(2nd)学习笔记(8)-2 (转)
    Java编程思想(2nd)学习笔记(8)-2 (转)[@more@]二.  Inner classes(内隐类)1.  内隐类的基本用法1)  如果要在外围class的non-static函数之外产生一个inn...
    99+
    2023-06-03
  • 《Java编程思想》学习笔记03、控制程序流
    大部分操作符只能操作基本类型(primitives),只有=、==和!=可以操作对象,另外String支持+和+=在=两边,右值(rvalue)可以是常数、变量或表达式,左值(lvalue)必须是一个变量,即必须有物理空间来存储rvalue...
    99+
    2023-06-03
  • Java学习笔记之面向对象编程精解
    目录包继承super 关键字finalprotected关键字组合多态抽象类接口面向对象编程(包、继承、组合、多态 、抽象类、接口) 包 包其实就是类的集合,其本质上其实就是一个文件...
    99+
    2024-04-02
  • Java学习笔记:npm异步编程实践指南?
    Java学习笔记:npm异步编程实践指南 在现代编程语言中,异步编程已经成为了一种必备的技能。在Java中,我们可以使用npm包管理器来进行异步编程。本篇文章将为您介绍npm异步编程的实践指南,并通过演示代码来帮助您更好地理解。 什么是np...
    99+
    2023-07-21
    学习笔记 npm 异步编程
  • 分布式Java编程入门教程:学习笔记必读!
    随着互联网的发展,分布式系统已经成为了大多数企业级应用的标配。在分布式系统中,Java作为一种优秀的编程语言,被广泛应用于实现系统的各种功能。分布式Java编程,就是利用Java语言来开发分布式系统,是Java程序员必须掌握的技能之一。 ...
    99+
    2023-08-31
    教程 学习笔记 分布式
  • linux shell编程学习笔记(3)
    1、什么是变量保存变化的数据——变量名:名称固定,由系统预设或用户自定义——变量值:根据用户设置、系统环境变化而变化2、如何定义变量——变量名=变量的值2.1变量名的规则(1)数字、字母、下划线(2)字母区分大小写(3)当变量名相同时,后赋...
    99+
    2023-01-31
    学习笔记 linux shell
  • [PYTHON] 核心编程笔记(16.P
    16.1 介绍16.1.1 什么是客户/服务器架构硬件的客户/服务器架构软件客户/服务器架构16.1.2 客户/服务器网络编程16.2 套接字: 通讯端点16.2.1 什么是套接字套接字是一种具有通讯端点感念的计算机网络数据结构16.2.2...
    99+
    2023-01-31
    核心 笔记 PYTHON
  • [PYTHON]核心编程笔记(15.Py
    核心笔记:查找与匹配的比较15.1.1 您的第一个正则表达式:15.2 正则表达式使用的特殊符号和字符常用正则表达式符号和特殊符号:记号       说明                                          举...
    99+
    2023-01-31
    核心 笔记 PYTHON
  • [PYTHON] 核心编程笔记(14.P
    在python中有多种运行外部程序的方法,比如,运行操作系统命令或另外的python脚本,或执行一个磁盘上的文件,或通过网络来运行文件在特定执行场景包括:在当前脚本继续运行创建和管理子进程执行外部命令或程序执行需要输入的命令通过网络来调用命...
    99+
    2023-01-31
    核心 笔记 PYTHON
  • [PYTHON] 核心编程笔记(13.P
    13.1 介绍类与实例:类与实例相互关联,类是对象的定义,而实例是"真正的实物",它存放了类中所定义的对象的具体信息下面的示例展示如何创建一个类:class MyNewObjectType(bases):    'define MyNewO...
    99+
    2023-01-31
    核心 笔记 PYTHON
  • [PYTHON] 核心编程笔记(17.P
    17.1 什么是因特网客户端17.2 文件传输17.2.1 文件传输因特网协议流行的有文件传输协议(FTP),Unix-to-Unix复制协议(UUCP),以及网页的超文本传输协议(HTTP),另外,还有(Unix下的)远程文件复制指令sc...
    99+
    2023-01-31
    核心 笔记 PYTHON
  • 《Python网络编程基础》笔记
                              python网络编程基础                           ================== Author: lujun9972 <luj...
    99+
    2023-01-31
    网络编程 基础 笔记
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作