Stream流和函数式编程

Java函数式编程之【流(Stream)的装饰】装饰器【map】和【flatMap】 函数式编程可分为三个步骤:Stream(流)的创建、Stream的中间操作和Stream的终止操作。其中Stream(流)的中间操作可以有n个,而流的终止操作只能有一个。本文详细介绍Stream(流)的中间操作。 阅读详情

Stream流

                 拼接流式模型

生产饮料 放瓶子   洗瓶子  装饮料  封口  装箱

java中的Stream并不会存储任何数据,而是按需计算.

数据源: 流的来源,可以是集合,数组等.
Pipelining:中间的每一步操作都会返回流对象本身,这样的操作可以串联为一个管道,可以对操作进行优化,比如延迟执行和短路.
内部迭代:以前的方法都是先有集合,在进行迭代(外部迭代),流可以调用foreach()方法直接遍历.(内部迭代)

当使用流的时候,通常包括三个步骤:
获取一个数据源(source) -> 数据转换 -> 执行操作获取想要的结果,每次转换原有Stream不变,返回一个新的Stream对象.


获取流:
1.所有的Conllection集合都可以.stream来获取流(list.stream() )

2.Stream接口的静态方法of可以获取数组对应的流(Stream.of(1,2,3,4) )

常用方法(除了终结方法,其他都是延迟方法)

  • 延迟方法:返回值类型仍为Stream流,支持链式调用.
  • 终结方法:返回值类型不在是Stream流,不支持链式调用(包括count,forEach)

例:

//创建一个list集合,存储姓名
List<String> list = new ArrayList<>();
list.add("张无忌");
list.add("周芷若");
list.add("赵敏");
list.add("张强");
list.add("张三丰");

/**
* Stream流写法 关注的是干什么,而不是怎么干
*/
//对list集合元素进行过滤, 只要张, 只要姓名长度为3的人
list.stream().filter((String name)->{
	return name.startsWith("张");
}).filter((String name)->{
	return name.length()==3;
});
//简化写法
list.stream()
        .filter(name -> name.startsWith("张"))
        .filter(name -> name.length() == 3)
        .forEach(name-> System.out.println(name));

System.out.println("------------------");
/**
* 传统写法
*/
//对list集合元素进行过滤, 只要张
ArrayList<String> a = new ArrayList<>();
for(String s : list) {
    if(s.startsWith("张")) {
        a.add(s);
    }
}
//对a集合进行过滤,只要姓名长度为3的人
ArrayList<String> b = new ArrayList<>();
for(String s : a) {
    if(s.length() == 3) {
        b.add(s);
    }
}
Iterator<String> iterator = b.iterator();
while(iterator.hasNext()) {
    String name = iterator.next();
    System.out.println(name);
}

Stream流属于管道流,只能被消费一次
第一个Stream流调用完毕方法,数据就会流转到下一个流上
而这时第一个流已经使用完毕,就会关闭了
第一个流就不在调用方法了

Filter方法(延迟方法,过滤流)

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

Map方法(延迟方法,映射)

Stream<Integer> integerStream = stream.map((String s) -> {
    return Integer.parseInt(s);
});

//Count方法 (终结方法,用于统计流中元素的个数)
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);

System.out.println(list.stream().count());

Limit方法(截取流)

Stream<String> stream = Stream.of("张无忌", "赵敏", "张三丰");
Stream<String> limit = stream.limit(2);
limit.forEach(name-> System.out.println(name));

//Skip方法(跳过流的几个元素)
Stream<String> stream = Stream.of("张无忌", "赵敏", "张三丰");

Stream<String> skip = stream.skip(1);
skip.forEach(name-> System.out.println(name));

Concat方法(将两个流合并)

Stream<String> streamA = Stream.of("张无忌", "赵敏", "张三丰");
Stream<String> streamB = Stream.of("喜羊羊", "灰太狼", "美羊羊");
Stream<String> concat = Stream.concat(streamA, streamB);
concat.forEach(name-> System.out.println(name));

集合练习题:

/**
 * Stream流方法
 */
//第一个队伍A只要3个名字的成员,放入新集合
//新集合只要前三个人
Stream<String> newA = listA.stream()
        .filter(name -> name.length() == 3)
        .limit(3);
//第二个队伍只要张姓
//新集合不要前两个人
Stream<String> newB = listB.stream()
        .filter(name -> name.startsWith("张"))
        .skip(2);
//结果集
Stream.concat(newA, newB).map(name->new Person(name)).forEach(p-> System.out.println(p));
 


/**
 * 传统方法
 */
ArrayList<String> newA = new ArrayList<>();
ArrayList<String> newB = new ArrayList<>();
//第一个队伍A只要3个名字的成员,放入新集合
for (String s : listA) {
    if(s.length() == 3) {
        newA.add(s);
    }
}
//新集合只要前三个人
for (int i = 3; i < newA.size(); i++) {
    newA.remove(i);
}

//第二个队伍只要张姓
for (String s : listB) {
    if(s.startsWith("张")){
        newB.add(s);
    }
}

//新集合不要前两个人
int i=0;
while(i < 2) {
    newB.remove(0);
    i++;
}

//结果集
ArrayList<String> result = new ArrayList<>();
for (String s : newA) {
    result.add(s);
}
for (String s : newB) {
    result.add(s);
}

result.forEach(name-> System.out.println(name));

System.out.println("--------------------------------");
//创建对象
ArrayList<Person> people = new ArrayList<>();
for (String s : result) {
    people.add(new Person(s));
}
people.forEach(name-> System.out.println(name));

函数式接口:(只有一个抽象方法的接口)

函数式接口在java中指:有且只有一个抽象方法的接口
java中的函数式接口编程体现就是Lambda

@Override
* 检测方法是否为重写方法
* 是:编译通过
* 否:编译失败
* @FunctionalInterface注解
* 检测这个接口是否为函数式接口
* 是:编译成功
* 否:编译失败  (没有抽象方法 或者抽象方法超过1个)

@FunctionalInterface
public interface MyFunctionInterface {
    /**
    * 定义一个抽象方法
    */
    public abstract void method();

     // void method2();
}

//1.可以传递一个接口
show(new MyFunctionInterfaceImpl());

//2.传递接口的匿名内部类 使用匿名内部类会创建一个class文件
show(new MyFunctionInterface() {
        @Override
        public void method() {
                System.out.println("匿名内部类");
        }
});

//3.使用Lambda表达式
show(()->{
        System.out.println("Lambda表达式");
});

//4.简化Lambda
show(()-> System.out.println("简化"));

使用匿名内部类会创建一个class文件,使用Lambda不会创建,建议使用Lambda表达式.

Lambda表达式的延时执行:有些场景的代码执行后,结果不一定会被使用,会造成性能浪费.而Lambda表达式是延时执行的,可以作为解决方案,提升性能.

性能浪费的日志案例:
日志可以帮我们快速定位问题,记录程序运行过程中的情况,以便项目的优化和监控.
一种典型的场景就是对参数进行有条件使用,例如对日志消息进行拼接后,在满足条件的情况下进行输出打印.

~使用Lambda表达式对日志案例进行优化

  • Lambda的特点:延迟加载
  • 使用前提:必须存在函数式接口
//定义一个显示日志的方法,方法的参数传递日志的等级和MessageBuilder接口
public static void showLog(int level,MessageBuilder mb) {
    //对日志的等级进行判断,如果为1级,调用方法
    if(level == 1) {
        System.out.println(mb.msgBuilder());
    }
}

public static void main(String[] args) {
//定义三个日志信息
String msgA = "Hello";
String msgB = "World";
String msgC = "Java";

//调用showLog方法,参数MessageBuilder是一个函数式接口,所以可以传递Lambda表达式
showLog(1,()->{
    return msgA + msgB + msgC;
});
/**
* 使用Lambda表达式作为参数传递,仅仅是吧参数传递到ShowLog中,
* 只有满足条件(等级为1)
* 才会调MessageBuilder中的方法进行字符串的拼接
* 条件不满足
* 就不会调用方法拼接
* 就不会造成性能浪费
*/
}

函数式接口作为返回值:
private static Comparator<Integer> getComparator() {

    //方法的返回值是一个接口,可以返回该接口的匿名内部类
    return new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o1-o2; //升序
        }
    };
}
//简化写法
private static Comparator<Integer> getCpt() {
        //方法的返回值是一个函数式接口,可以返回Lambda表达式
        return (Integer o1,Integer o2)->{ return o1-o2;};
}

函数式接口作为参数:
public static void startThread(Runnable runnable) {
    //开启线程
    new Thread(runnable).start();
}


public static void main(String[] args) {
    //使用startThread方法,方法的参数是一个接口,那么我们可以传递这个接口的匿名内部类.
    startThread(new Runnable() {
        @Override
        public void run() {
                System.out.println(Thread.currentThread().getName()+"线程启动了");
        }
    });

    //调用startThread方法,方法的参数是一个函数式接口,所以可以使用Lambda表达式
    startThread(()->
        System.out.println(Thread.currentThread().getName()+"线程启动了")
    );
}
【深度学习新浪潮】气候预测模型的研发进展一览(2025年版) 模型类型核心优势适用场景不足ARIMA(统计模型)简单高效、可解释性强短期单变量预测非线性、长时依赖建模差随机森林(机器学习)多特征融合、抗噪声中短期多因素预测空间相关性、时序趋势捕捉弱LSTM(深度学习)长时依赖建模、端到端中长期时序预测物理一致性差、数据需求量大物理知情AI物理规律约束、高可靠性极端天气、长期气候变化模型复杂、计算成本高。 阅读详情

相关推荐

大样本EEG公共数据集汇总

描述: OpenNeuro平台包含多个认知障碍相关的EEG数据集,例如针对轻度认知障碍(MCI)或阿尔茨海默病(AD)的研究。描述: 天普大学医院EEG语料库包含大量临床EEG记录,可通过元数据筛选出与认知障碍相关的片段(如诊断标签包含dementia或MCI)。描述: ADNI主要提供多模态神经影像数据(MRI/PET),但部分合作研究整合了EEG数据。样本量: 部分数据集包含100+被试(例如结合MRI与EEG的多模态数据)。样本量:30,000+ EEG记录(持续更新,全球最大临床EEG数据库)。

谁人打的太极拳的博客 1764

跟我学代码架构设计模式之--函数式编程和高阶函数和流式编程

道曰:形而上者谓之道。在事物的所有表象之外,必然有一种根本统治着它们--道。 上篇两篇我对函数式编程有了初步的分析,这一篇我尝试分析下如何使用函数式编程思想来实现业务逻辑。 一、根本思想 用函数式思想来解决问题的根本原理就是:1 一个函数接收参数 2 进行业务处理 3生成返回值 4 将返回值传递给下一个函数,下一个函数继续上面的1-4步骤,多个函数组合来完成业务,通过参数传递传递初始数据或者...

孔令宽的专栏 513

基于LTspice的共模电感差模/共模插入损耗仿真指南

在电源与EMC设计领域,插入损耗是衡量滤波器件抑制噪声能力的核心指标。共模电感作为EMI滤波器中最常见的元器件之一,其差模与共模插入损耗特性直接影响整体滤波方案的合规性。然而,仅依赖规格书曲线往往难以覆盖真实应用中的阻抗条件,借助SPICE仿真工具进行电路级验证已成为工程师常用的手段。LTspice凭借其轻量、高效的交流分析能力,能够帮助设计者快速搭建共模电感等效模型,并通过调整耦合系数、寄生电容等参数,还原漏感与谐振行为。本文以Wurth Elektronik的WE 744821201型号为例,从基本测试

weixin_27252001的博客 293

Java8 新特性 Stream

Java8新特性 ----> Lambda表达式:

北执南念的博客 824

电子取证之服务器取证思路

服务器取证是一个技术性很强的领域,涉及到多个环节,包括网站重构、网站代码分析、容器分析等。数据库密码的获取通常通过查看配置文件、日志文件、备份等途径,同时可以通过一些绕过技术如禁用身份验证来获取权限。对于不同的数据库,需要根据其特性采取相应的应对方法和命令。

2401_84830066的博客 2491

【算法】图解A* 搜索算法

A* 算法是启发式搜索算法,是根据Dijkstra算法改进而来。 问题引入 如下图所示,S为起始(start)节点,G为目标(goal)节点。 节点之间连线是两点的路径长度,如A到E的路径长度c(A,E) = 9。 节点旁的h值时当前节点到达目标节点(G)的预估值,如h(A)=15, 表示从当前点A到达目标点G的估计路径长度为15,此处h(x)即为启发函数,启发函数的设计有很多方法,具体可......

zhuhua造轮子的博客 4万+

重拾Java基础知识:函数式与流式编程

集合优化了对象的存储,而流和对象的处理有关。

码农的艺术 1340

数学建模学习(120):使用Python实现基于AHP的供应商选择分析

使用Python实现基于AHP的供应商选择分析

全栈川川 915

【Java】Java函数式编程以及流的操作

Java函数式编程入门

Gragon_qx的博客 1761

今日指数项目之实时流数据采集【六】

实时数据采集代码

Maynor的博客 2147

USB驱动(URB)

本文介绍了Linux内核中USB驱动开发的核心概念URB(USB Request Block)。URB是主机与USB设备间传输数据的抽象结构体,包含目标设备、端点信息、数据缓冲区等关键字段。文章详细解析了URB的生命周期(分配、填充、提交、回调、释放)、四种传输类型(控制、批量、中断、等时)及其应用场景,并提供了鼠标设备的中断传输示例代码。最后强调了URB使用注意事项,包括DMA缓冲区分配、错误处理和资源释放等。URB作为USB驱动与内核通信的桥梁,是构建稳定USB驱动程序的基础。

m0_49476241的博客 915

java8函数式编程和流(Stream)总结

目录1、相关概念2、各种编程思想比较2.1、函数式编程vs面向对象编程2.2 声明式编程vs命令式编程3、流式编程3.1 流(Steam)vs集合(Collection)3.2 流操作3.3 SteamAPI4、并发编程4.1 流vs并发4.2 并发vs并行4.3 Java并发编程的演进之路5、函数式编程和流给Java带来了什么 1、相关概念 【1】函数(Function) 在java中,函数就是...

geekluxun的专栏 958

【ARMv9 DSU-120 系列 1 -- DSU-120 DynamIQ 概述】

ARMv9架构中的DynamIQ™ Shared Unit-120(简称DSU-120)为一组基于Cortex-A类架构的核心提供了共享的L3内存系统、窥探控制(snoop control)和 过滤(filtering) 以及其他支持集群运作的控制逻辑。这个集群被称为DSU-120 DynamIQ™集群。此外,所有连接到片上系统(SoC)的外部接口也都是通过DSU-120提供的。一个DSU-120 DynamIQ™集群可以包含1到14个核心,且同一集群中可包含多达三种不同类型的核心。

CodingCos的博客 1188

24.函数式编程和Stream流

Java中的函数式编程和Stream流

LMY0210的博客 272

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

函数式编程和Stream流常用方法

Stream流常用方法

qq_48128672的博客 1068

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Java函数式编程Lambda和Stream流

为什么要用函数式编程,函数式编程所用到的Lambda、Stream的原理是什么,本文做了详细介绍和实操流程

StillTogether的博客 418

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

四大函数式接口和stream流编程

理解并实现四大函数式接口和stream流的操作。

xiaonandaima的博客 335

函数式编程之Lambda表达式和Stream流

在方法调用传入匿名内部类时,在匿名内部类使用idea的快捷键: 可以选定lambda表达式。多线程创建方式: lambda创建线程: 自定义方法: 普通调用方法: 简化: 自定义方法2: 普通调用: lambda简化: 自定义方法3: 普通方法调用: lambda优化: 自定义代码3: 普通调用: lambda: 1.1.2 lambda表达式省略规则 参数类型可以省略; 方法体只有一句代码时大括号和唯一的代码的分号可以省略; 方法只有一个参数

风间琉璃の博客 474

JAVA8特性 & Stream流 & 函数式编程Lambda表达式 & 双冒号(::)的用法和原理

Lambda表达式可以作为函数式接口的实例,函数式接口是只有一个抽象方法的接口。将每个元素通过给定的映射函数转换为另一种类型,并返回一个新的Stream。将流中的元素根据指定的键和值的提取函数收集到一个并发的 Map 中。A:表示用于累积部分结果的对象的类型,也可以看作是中间结果的类型。根据给定的条件过滤出符合条件的元素并返回一个新的Stream。将流中的元素根据指定的键和值的提取函数收集到一个 Map 中。根据指定的条件过滤流中的元素,并将结果收集到一个集合中。

qq_43571809的博客 1024

函数式编程学习-SICP-LISP-流STREAM的实现-流编程思路和惰性/延时求值

原教学视频 如何实现流: 在流的这一课,重新构造了CONS 比如 (CONS-STREAM X Y) (HEAD S) (TAIL S) THE-EMPTY-STREAM 对于任意的x和y,有 HEAD (CONS-STREAM X Y) =X TAIL (CONS-STREAM X Y) =Y 以上可以是表的另外一种说法。 有了以上内容,我们可以定义很多函数: 可以说,流是你设计的用来满足你约定的接口的一个工具。 回溯搜索问题上,我们的方法会获得全部的解。但实际情况中,我们不需要获得那么

迷你小猴子村庄 399

Java 8函数式编程笔记(二)- 集合和流(stream)

Java 8函数式编程笔记(二)- 集合和流(stream)随便说说:上一篇我们讲了Java 8新增了很多函数接口,这些函数接口是对运算的高度抽象,在这些抽象的基础上,我们可以进一步实现一些具体的API,方便我们的操作。Java 8对核心类库的集合进行了改进,同时引进了新的流(stream)。流式操作可以让程序员在更高的抽象层次上对集合进行操作。

斑点喵的博客 736

java8函数式编程学习(一):lambada表达式和stream流的使用

jdk8的新特性中的lambada和stream流的简单使用。

weixin_45037073的博客 1198

函数式编程学习-SICP-LISP-流STREAM的实现-流编程思路和惰性/延时求值2

如何与时间解耦 流式程序 看待流的方法:即一下子处理了整个流。 准备例子: 第一个例子:将两个流相加。 第二个例子:运用到流上的所有项目 一个由1组成的无尽列表 如何定义整数: 定义斐波那契数列 何做到不要显式定义很多delay? 让整个底层都延时。让delay自动内建在语言之中。 这种语言叫做“正则序求值”(normal order)语言。而我们一直用的语言叫做application-order语言。即先求参数,再求值。而前者把整个参数放到函数中。 如果这样做了,cons也会自动变成cons-

迷你小猴子村庄 492

函数式编程-Stream流

函数式编程中的Stream流是Java 8中引入的一种新特性,用于处理集合数据。它是一种更简洁、更灵活和更可读的方式来处理集合数据,旨在简化集合框架的操作。

weixin_47110096的博客 1518

函数式编程-Stream 流

Lambda是 JDK8 中一个语法糖。可以看成是一种语法糖,他可以从对某些匿名内部类的写法进行简化。它是函数式编程思想的一个重要体现。让我们不用关注是什么对象。而是更关注我们对数据进行了什么操作。Java8的Stream使用的是函数式编程模式,如同它的名字一样,它可以被用来对集合或数组进行链状流式操作。可以更方便的对集合或数组操作。我们在编写代码的时候出现最多的就是空指针异常。所以在很多情况下我们需要做各种非空的判断。if(author!= null) {尤其是对象中的属性还是一个对象的情况下。

410的博客 1079
上一篇: 生产者消费者模型
下一篇: MySQL数据库基本语法,数据库设计,事务,多表查询及练习题
Java-fly
博客等级 码龄9年 13粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值