Java 8 新特性之Stream流(二)关键

news2025/1/16 5:00:00

继续探索流API的高级功能之前,我们先从接口级别全面了解一下流API,这个对于我们来说是至关重要的。下面是一张流API关键知识点的UML图。

流API UML

流API UML

流API定义的几个接口,都是在java.util.stream包中的.其中上图中的BaseStream接口是最基础的接口,它提供了所有流都可以使用的基本功能:

public interface BaseStream<T, S extends BaseStream<T, S>> extends AutoCloseable {
//....先忽略这些具体的细节
}

由这个接口的定义我们得知,BaseStream是一个泛型接口,它有两个类型参数T和S, 其中T指定了流中的元素的类型,并且由<S extends BaseStream<T, S>>可以知道S必须为BaseStream或BaseStream子类(换句话说,就是S必须是扩展自BaseStream的)。BaseStream继承了AutoCloseable接口。这个接口主要是简化了关闭资源的操作。但是像平时我们操作的集合或数组,基本上都不会出现关闭流的情况。

//由BaseStream接口派生出的流接口包括IntStream ,LongStream,DoubleStream ,Stream<T>
public interface IntStream extends BaseStream<Integer, IntStream> {
}
public interface LongStream extends BaseStream<Long, LongStream> {
}
public interface DoubleStream extends BaseStream<Double, DoubleStream> {
}

//这是最具代表性的接口
public interface Stream<T> extends BaseStream<T, Stream<T>> {
//....先忽略这些具体的细节
}

由于Stream接口是最具代表性的,所以我们就选择它来讲解,其实在我们学完Stream接口,其它的三个接口,在使用上基本是一致的了,我们上一篇的Demo基本上也是使用Stream接口来做的练习。我们回想一下:在上一个Demo中我们通过集合框架的stream()方法,就能返回一个流了,它的返回类型就是Stream,比如我们Stream,由此得知,Stream接口里的类型参数T就是流中的元素的类型。

BaseStream详解:

public interface BaseStream<T, S extends BaseStream<T, S>> extends AutoCloseable {
     Iterator<T> iterator();//line2
     Spliterator<T> spliterator();//line3
     boolean isParallel();//line4
     S sequential();//line5
     S parallel();//line6
     S unordered();//line7
     S onClose(Runnable closeHandler);//line8
     @Override
     void close();//line10
}
```java

* **Iterator<T> iterator();**  *`//line2`*
获得流的迭代器,并返回对该迭代器的引用(终端操作)
* **Spliterator<T> spliterator();** *`//line3`*
获取流的spliterator,并返回其引用(终端操作)
* **boolean isParallel();** *`//line4`*
如果调用流是一个并行流,则返回true;如果调用流是一个顺序流,则返回false* **S sequential();** *`//line5`*
基于调用流,返回一个顺序流。如果调用流已经是顺序流了,就返回该流。(中间操作)
* **S parallel();** *`//line6`*
基于调用流,返回一个并行流。如果调用流已经是并行流了,就返回该流。(中间操作)
* **S unordered();** *`//line7`*
基于调用流,返回一个无序流。如果调用流已经是无序流了,就返回该流。(中间操作)
* **S onClose(Runnable closeHandler);** *`//line8`*
返回一个新流,closeHandler指定了该流的关闭处理程序,当关闭该流时,将调用这个处理程序。(中间操作)
* **void close();** *`//line10`*AutoCloseable继承来的,调用注册关闭处理程序,关闭调用流(很少会被使用到)

“终端操作”&“中间操作”

细心的同学应该注意到了,BaseStream接口里面的很多方法都在最后标识了(终端操作)和(中间操作),它们之间的区别是非常重要的。

  • 终端操作 会消费流,这种操作会产生一个结果的,比如上面的 iterator()和 spliterator(),以及上一篇中提到的min()和max(),或者是执行某一种操作,比如上一篇的forEach(),如果一个流被消费过了,那它就不能被重用的。

  • 中间操作 中间操作会产生另一个流。因此中间操作可以用来创建执行一系列动作的管道。一个特别需要注意的点是:中间操作不是立即发生的。相反,当在中间操作创建的新流上执行完终端操作后,中间操作指定的操作才会发生。所以中间操作是延迟发生的,中间操作的延迟行为主要是让流API能够更加高效地执行。

"中间操作"的状态

流的中间操作,可以为分无状态操作有状态操作两种,在无状态操作中,在处理流中的元素时,会对当前的元素进行单独处理。比如:谓词过滤操作,因为每个元素都是被单独进行处理的,所有它和流中的其它元素无关,因此被称为无状态操作;而在有状态操作中,某个元素的处理可能依赖于其他元素。比如查找最小值,最大值,和排序,因为他们都依赖于其他的元素。因此为称为有状态操作。当需要进行并行处理流时,有状态的操作和无状态的区别是非常重要的,因为有状态操作可能需要几次处理才能完成,后面的文章我将会给大家详细地讲,现在只需要正常学习下去就可以了

另外,指出一点,如果大家了解泛型的话,应该知道,泛型的类型参数只能是引用类型,因此Stream操作的对象只能是引用类型的,不能用于基本类型。当然官方早已考虑到这一点了,前面你们看到的IntStream,LongStream,DoubleStream就是官方给我们提供的处理基本类型的流了。此处是不是应该给他们掌声!

Stream详解

在有了前面的那些知识作铺垫之后,学Stream接口应该会顺风顺水了。还是先看看Stream的详情先:

public interface Stream<T> extends BaseStream<T, Stream<T>> {
    Stream<T> filter(Predicate<? super T> predicate);//line2
    <R> Stream<R> map(Function<? super T, ? extends R> mapper);//line3
    IntStream mapToInt(ToIntFunction<? super T> mapper);//line4
    LongStream mapToLong(ToLongFunction<? super T> mapper);
    DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);
    <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
    IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper);
    LongStream flatMapToLong(Function<? super T, ? extends LongStream> mapper);
    DoubleStream flatMapToDouble(Function<? super T, ? extends DoubleStream> mapper);
    Stream<T> distinct();
    Stream<T> sorted();//line12
    Stream<T> sorted(Comparator<? super T> comparator);//line13
    Stream<T> peek(Consumer<? super T> action);
    Stream<T> limit(long maxSize);
    Stream<T> skip(long n);
    void forEach(Consumer<? super T> action);//line17
    void forEachOrdered(Consumer<? super T> action);//line18
    Object[] toArray();
    <A> A[] toArray(IntFunction<A[]> generator);
    T reduce(T identity, BinaryOperator<T> accumulator);
    Optional<T> reduce(BinaryOperator<T> accumulator);
    <U> U reduce(U identity,
                 BiFunction<U, ? super T, U> accumulator,
                 BinaryOperator<U> combiner);
    <R> R collect(Supplier<R> supplier,
                  BiConsumer<R, ? super T> accumulator,
                  BiConsumer<R, R> combiner);
    <R, A> R collect(Collector<? super T, A, R> collector);
    Optional<T> min(Comparator<? super T> comparator);//line30
    Optional<T> max(Comparator<? super T> comparator);//line31
    long count();
    boolean anyMatch(Predicate<? super T> predicate);
    boolean allMatch(Predicate<? super T> predicate);
    boolean noneMatch(Predicate<? super T> predicate);
    Optional<T> findFirst();
    Optional<T> findAny();

    // Static factories

    public static<T> Builder<T> builder() {
        return new Streams.StreamBuilderImpl<>();
    }


    public static<T> Stream<T> empty() {
        return StreamSupport.stream(Spliterators.<T>emptySpliterator(), false);
    }


    public static<T> Stream<T> of(T t) {
        return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false);
    }


    @SafeVarargs
    @SuppressWarnings("varargs") // Creating a stream from an array is safe
    public static<T> Stream<T> of(T... values) {
        return Arrays.stream(values);
    }


    public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {
        Objects.requireNonNull(f);
        final Iterator<T> iterator = new Iterator<T>() {
            @SuppressWarnings("unchecked")
            T t = (T) Streams.NONE;

            @Override
            public boolean hasNext() {
                return true;
            }

            @Override
            public T next() {
                return t = (t == Streams.NONE) ? seed : f.apply(t);
            }
        };
        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
                iterator,
                Spliterator.ORDERED | Spliterator.IMMUTABLE), false);
    }


    public static<T> Stream<T> generate(Supplier<T> s) {
        Objects.requireNonNull(s);
        return StreamSupport.stream(
                new StreamSpliterators.InfiniteSupplyingSpliterator.OfRef<>(Long.MAX_VALUE, s), false);
    }


    public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) {
        Objects.requireNonNull(a);
        Objects.requireNonNull(b);

        @SuppressWarnings("unchecked")
        Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
                (Spliterator<T>) a.spliterator(), (Spliterator<T>) b.spliterator());
        Stream<T> stream = StreamSupport.stream(split, a.isParallel() || b.isParallel());
        return stream.onClose(Streams.composedClose(a, b));
    }
}
  • Stream filter(Predicate<? super T> predicate); //line2
    产生一个新流,其中包含调用流中满足predicate指定的谓词元素(中间操作)
  • Stream map(Function<? super T, ? extends R> mapper); //line3
    产生一个新流,对调用流中的元素应用mapper,新流中包含这些元素。(中间操作)
  • IntStream mapToInt(ToIntFunction<? super T> mapper); //line4
    对调用流中元素应用mapper,产生包含这些元素的一个新IntStream流。(中间操作)
  • Stream sorted(); //line12
  • Stream sorted(Comparator<? super T> comparator); //line13`
    产生一个自然顺序排序或者指定排序条件的新流(中间操作)
  • void forEach(Consumer<? super T> action); //line17
  • void forEachOrdered(Consumer<? super T> action); //line18
    遍历了流中的元素(终端操作)
  • Optional min(Comparator<? super T> comparator) //line30
  • Optional max(Comparator<? super T> comparator); //line31
    获得流中最大最小值,比较器可以由自己定义,也可以使用JDK提供的(终端操作)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

每日记录自己的Android项目(二)—Viewbinding,WebView,Navigation

今日想法今天是想把做一个跳转页面的时候调到H5页面去&#xff0c;但是这个页面我用app来承载&#xff0c;不要调到浏览器去。所以用到了下方三个东西。Viewbindingbuild.gradle配置首先在app模块的build.gradle里添加一下代码默认情况下&#xff0c;每一个布局xml文件都会生成…

【Linux学习】基础IO——理解缓冲区 | 理解文件系统

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《Linux学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 基础IO☕理解缓冲区&#x1f9c3;缓冲区的共识&#x1f9c3;缓冲区的位置&#x1f9c3;缓冲区的刷…

Spring Boot+Vue前后端分离项目练习03之网盘项目文件夹创建及文件查询接口开发

1.集成Swagger 3接口文档 在前后端分离的项目中&#xff0c;接口文档的存在十分重要。swagger 是一个自动生成接口文档的工具&#xff0c;在需求变更十分频繁的情况下&#xff0c;手写接口文档是效率十分低下&#xff0c;这时swagger自动生生文档的的作用就体现出来了&#xf…

【uni-app教程】UniAPP 常用组件和 常用 API 简介# 知心姐姐聊天案例

五、UniAPP 常用组件简介 uni-app 为开发者提供了一系列基础组件&#xff0c;类似 HTML 里的基础标签元素&#xff0c;但 uni-app 的组件与 HTML 不同&#xff0c;而是与小程序相同&#xff0c;更适合手机端使用。 虽然不推荐使用 HTML 标签&#xff0c;但实际上如果开发者写了…

华为机试题:HJ105 记负均正II(python)

文章目录&#xff08;1&#xff09;题目描述&#xff08;2&#xff09;Python3实现&#xff08;3&#xff09;知识点详解1、input()&#xff1a;获取控制台&#xff08;任意形式&#xff09;的输入。输出均为字符串类型。1.1、input() 与 list(input()) 的区别、及其相互转换方…

【Kubernetes】第十七篇 - ECS 服务停机和环境修复

一&#xff0c;前言 上一篇&#xff0c;介绍了 Secret 镜像的使用&#xff1b; 三台服务每天大概 15 块钱的支出&#xff0c;用一个月也是不少钱&#xff1b; 闲时可以停掉&#xff0c;这样每天只有 4 块钱支出&#xff0c;剩下一大笔&#xff1b; ECS 服务停机后公网 IP 会…

移除元素(每日一题)

目录 一、题目描述 二、题目分析 2.1 方法一 2.1.1 思路 2.1.2 代码 2.2 方法二 2.2.1 思路 2.2.2 代码 一、题目描述 题目链接&#xff1a;27. 移除元素 - 力扣&#xff08;LeetCode&#xff09; 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数…

【Maven】P1 Maven 基础知识

Maven 基础知识Maven基础仓库坐标快速坐标生成网站国内镜像仓库前言 本节&#xff1a;Maven第一节内容&#xff0c;记录maven是什么&#xff0c;解决了什么问题&#xff0c;进而推出他的作用&#xff1b;然后介绍maven中两个重要概念&#xff0c;仓库与坐标。 下一节&#xff1…

TIA博途中使用SCL语言实现选择排序算法并封装成FC全局库

TIA博途中使用SCL语言实现选择排序算法并封装成FC全局库 选择排序算法包括升序和降序2种: 升序排列: 第一轮从数据源中找到最小值排在第一位,第二轮从剩下的数据中寻找最小值排在第二位,依次类推,直到所有数据完成遍历;降序排列: 第一轮从数据源中找到最大值排在第一位,…

centOS 编译strongswan

安装编译环境 yum groupinstall "Development Tools" 编译strongswan Download strongSwan: wget https://download.strongswan.org/strongswan-x.x.x.tar.bz2 Unpack the tarball and navigate into the directory: tar xjf strongswan-x.x.x.tar.bz2; cd strong…

Editor.md 的使用方法及图片处理

目录1. 资源下载2. 生成页面2.1 编辑和预览页面2.2 文本渲染页面3. 图片上传3.1 前端配置3.2 后端接口4. 图片粘贴1. 资源下载 官网下载 gitee 下载 2. 生成页面 2.1 编辑和预览页面 将资源&#xff08;精简后 Editor.md 资源1&#xff09;导入项目&#xff1a; 按照官方教…

nvidia Jetson nano Linux内核编译

今天编译了nvidia 的jetson nano的内核。在网上找到的资料都比较老了。现在官网的最新版本是35.1.结合之前看到的博客的内容。关键是内核源码和交叉编译器的下载。找到官方文档后,编译成功!并且官方的文档是有一个编译脚本的。看之前的资料都是给出的命令,不知道这个nvbuild…

库函数qsort的使用以及模拟实现

首先&#xff0c;qsort函数是个库函数 那么就有头文件 #include<stdlib.h>这个函数的实现是利用快速排序的方法实现的 下面是该函数的参数//void qsort(void* base, //指向了待排序数组的第一个元素 // size_t num, //待排序的元素个数 // size_t …

FLoyd算法的入门与应用

目录 一、前言 二、FLoyd算法 1、最短路问题 2、Floyd算法 3、Floyd的特点 4、Floyd算法思想&#xff1a;动态规划 三、例题 1、蓝桥公园&#xff08;lanqiaoOJ题号1121&#xff09; 2、路径&#xff08;2021年初赛 lanqiaoOJ题号1460&#xff09; 一、前言 本文主要…

Cannot start compiler The output path is not specified for module mystatic(已解决)

1.背景&#xff1a;今天在idea上写了一些代码&#xff0c;右键run竟然跑不起来了&#xff0c;而且右下角的Event Log还报错。报错内容如下图&#xff1a;2.报错原因&#xff1a;项目代码和编译器的输出路径不在一块&#xff0c;导致idea无法找到模块的output path&#xff08;输…

Docker--(六)--Docker资源限制

前言系统压力测试Cpu资源限制Mem资源限制IO 资源限制【扩展】 1.前言 在使用 Docker 运行容器时&#xff0c;一台主机上可能会运行几百个容器&#xff0c;这些容器虽然互相隔离&#xff0c;但是底层却使用着相同的 CPU、内存和磁盘资源。如果不对容器使用的资源进行限制&#x…

VUE中给对象添加新属性时,界面不刷新怎么办

一、直接添加属性的问题 举例&#xff1a; 定义一个p标签&#xff0c;通过v-for指令进行遍历 然后给botton标签绑定点击事件&#xff0c;我们预期点击按钮时&#xff0c;数据新增一个属性&#xff0c;界面也 新增一行。 <p v-for"(value,key) in item" :key&qu…

18.用于大型程序的工具

文章目录用于大型程序的工具18.1异常处理18.1.1抛出异常栈展开栈展开过程中对象被自动销毁析构函数与异常异常对象18.1.2捕获异常查找匹配的处理代码重新抛出捕获所有异常的处理代码18.1.3函数try语句块与构造函数18.1.4noexcept异常说明违反异常说明异常说明的实参noexcept运算…

Potions (Hard Version) and (Easy Version)(背包DP + 反悔贪心)

[TOC](Potions (Hard Version) and (Easy Version)) 一、Potions(Easy Version) 1、问题 2、分析&#xff08;背包DP 贪心&#xff09; 简而言之就是我们需要从左到右开始选数字&#xff0c;选的过程中我们需要保证我们选的数字的和始终是大于等于0的&#xff0c;在满足这个…

零售电子货架标签解决方案

数字价格标签是一种新的零售趋势。它(ESLs)弥补了店内管理面临的挑战&#xff0c;是新零售的里程碑。电子货架标签(ESLs)为顾客开启了一段愉快的旅程。他们希望更多地参与到购物环境中&#xff0c;并从与商店的更深入互动中受益。 什么是电子货架标签&#xff1f; ESL系统用于…