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()+"线程启动了")
    );
}
CANopen PDO 配置實戰:3步完成0x1800-0x1A00物件字典映射與事件觸發 本文详细解析CANopen PDO配置实战,通过3个关键步骤完成0x1800-0x1A00对象字典映射与事件触发设置。重点介绍COB-ID位域解析、映射参数配置及事件触发优化,帮助工程师实现工业自动化设备间毫秒级实时数据交换,提升系统通信效率。 阅读详情

相关推荐

同济土木非0基础三个月跨考复旦计算机攻略

跨考cs攻略前言我cs专业课如何复习How to start from zero简历其他复试 前言 建议多去工地/化工厂涡轮增压一下 我 同济土木gpa 3.2/5 挂科 * n 辣鸡项目 * n (padding 简历) 21考复旦计算机专硕 10月-12月 学习+复习 总分392 政治 68;背肖4即可 英语二 78 裸考,(高考英语140+);做点真题,建议据自己情况准备 数学二 142 ;(高考数学接近满分);做真题+模拟题,每天写一张试卷 专业课 104 ,考试生病了,下文展开。 cs专业课

piglake的博客 7238

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

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

孔令宽的专栏 513

Hive中的四种排序方式(order by,sort by,distribute by,cluster by)使用与区别详解

在平时的Hive数仓开发工作中经常会用到排序,而Hive中支持的排序方式有四种,这里结合具体的案例详细介绍一下他们的使用与区别: order by sort by distribute by cluster by 一、order by(全局排序) 1、作用:全局排序,只有一个reducer。 order by 会对输入做全局排序,因此只有一个reducer(多个reducer无法保证全局有序),也正因为只有一个reducer,所以当输入的数据规模较大时会导致计算时间较长。   set hive.mapr

weixin_43230682的博客 1万+

Java8 新特性 Stream

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

北执南念的博客 824

【论文复现】自动化细胞核分割与特征分析

HoVer-Net是一种精心设计的多分支深度学习网络架构,专为处理复杂的多组织显微图像中的细胞核实例分割与精确分类任务而开发。该网络通过创新的策略,不仅有效解决了细胞核在密集聚集区域难以准确区分的问题,还实现了对每个独立细胞核类型的细致分类。此外,HoVer-Net还引入了专门的上采样分支,这一设计旨在对每个成功分割出的细胞核实例进行进一步的核类型分类。这一分支利用高级语义信息,结合精心设计的分类策略,能够准确判断每个细胞核的所属类型,为医学研究提供了宝贵的细胞水平信息。

2201_75366661的博客 1981

告别环境报错:Qt Creator里配置Android SDK/NDK/JDK路径的完整避坑指南

本文详细解析了在Qt Creator中配置Android SDK/NDK/JDK路径的完整避坑指南,深入探讨了路径检测的内部机制、构建套件配置的隐藏逻辑以及项目级与全局配置的优先级。通过实际案例和高级排查技巧,帮助开发者解决常见的环境报错问题,提升Qt安卓开发效率。

weixin_42548829的博客 238

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

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

码农的艺术 1340

Visual Studio Code 打开java项目

在 Visual Studio Code 中打开并运行一个 Java 项目之前,你需要确保你已经完成了一些初始设置。

2675

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

Java函数式编程入门

Gragon_qx的博客 1761

常用元器件使用方法3:电平转换芯片74LVC1T45的使用方法

介绍: 74LVC1T45是一个单位双向可控电平转换芯片。   芯片特性: 1、宽供给电压范围:1.65V到5.5V; 2、3.3V时,可输出24mA电流; 3、最大16uA电能损耗; 4、高噪音抑制;   型号:   引脚: VCC(A) 1 A端和DIR电源 GND 2 地 A 3 数据输入/输出 B 4 ...

snmplink的博客 1万+

逻辑判断1-逻辑基础知识

判断推理学习笔记

小y的学习笔记 2133

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

USB2.0协议解读

就写到这吧,其他协议层等属于软件需要了解的东西了。简单看了下,本文总结的有点乱,有两个原因吧,其一是理解的不够透彻,无法用简单明了的语言总结;其二是感觉这个协议文档章节划分的也不是很好,有点大杂烩。

qflook的博客 3674

24.函数式编程和Stream流

Java中的函数式编程和Stream流

LMY0210的博客 272

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

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

Stream流常用方法

qq_48128672的博客 1068

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Java函数式编程Lambda和Stream流

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

StillTogether的博客 418

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

四大函数式接口和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、付费专栏及课程。

余额充值