当前位置: 首页 > news >正文

Java基础全套教程(十一)—— 函数式编程详解

Java基础全套教程(十一)—— 函数式编程详解

前言

JDK8 是 Java 语言发展史上极具里程碑意义的版本,其中最重要的两大更新就是Lambda表达式Stream流式编程,二者共同构成了 Java 的函数式编程体系。

在 JDK8 之前,Java 是纯粹的面向对象编程语言,所有代码都必须依托类与对象实现,即使是简单的逻辑执行,也需要通过匿名内部类、重载方法等繁琐方式编写,代码冗余度极高。而函数式编程的引入,让 Java 兼具了面向对象与函数式编程的优势,允许将代码逻辑(方法)作为参数、变量、返回值传递,极大简化了集合操作、逻辑回调、流式数据处理的代码,让代码更简洁、优雅、高效。

本节课将从零详解函数式编程核心思想、Lambda表达式、函数式接口、方法引用、变量捕获、内置核心函数接口以及 Stream 流式编程,全程搭配全新原创实操案例,无冗余习题、无老旧复刻代码,适配零基础学习与进阶开发。

一、函数式编程核心思想

1.1 什么是函数式编程

编程范式主要分为面向对象编程、函数式编程、命令式编程等。

面向对象编程:核心思想是“万物皆对象”,通过封装对象、调用对象方法完成业务逻辑,关注谁来做

函数式编程:核心思想是“函数即数据”,将方法(函数)作为一等公民,可以独立定义、赋值、传参、返回,关注做什么,弱化对象的束缚,专注逻辑本身。

1.2 Java函数式编程的核心价值

  • 代码极简:彻底替代臃肿的匿名内部类,一行代码实现复杂逻辑。

  • 逻辑清晰:链式编程风格,数据处理流程一目了然,告别嵌套冗余代码。

  • 支持流式处理:结合Stream流,快速实现集合过滤、排序、映射、统计等复杂操作。

  • 便于并行计算:Stream原生支持并行流,轻松实现多线程数据处理,提升效率。

二、Lambda表达式核心基础

2.1 Lambda表达式简介

Lambda表达式是 JDK8 推出的函数式编程核心语法,是对匿名内部类的极简优化,专门用于简化函数式接口的实例化与方法实现。

传统Java语法中,无法将一段代码逻辑赋值给变量;而Lambda表达式实现了这一能力,它可以将一段动态代码块封装为一个“函数对象”,赋值给函数式接口变量,实现逻辑的动态传递。

2.2 函数式接口(Lambda的前提)

函数式接口是Lambda表达式唯一的使用载体,没有函数式接口,Lambda表达式无法使用。

2.2.1 定义规范

满足以下条件的接口即为函数式接口:接口中有且仅有一个抽象方法

核心注意点:接口中可以包含多个默认方法(default修饰)、静态方法、私有方法,这些非抽象方法不影响函数式接口的判定。

2.2.2 @FunctionalInterface注解

该注解是函数式接口的标识与校验注解,作用如下:

  • 显式声明当前接口为函数式接口;

  • 编译期强制校验,接口中一旦出现多个抽象方法,直接编译报错,避免接口失效;

  • 仅为编译校验,即使不添加该注解,满足单抽象方法的接口依然是函数式接口。

2.2.3 自定义函数式接口案例

// 无参无返回值函数式接口@FunctionalInterfacepublicinterfaceAction{voidexecute();}// 单参数无返回值函数式接口@FunctionalInterfacepublicinterfaceConsumerTask{voidaccept(Stringcontent);}// 多参数有返回值函数式接口@FunctionalInterfacepublicinterfaceComputeTask{intcalculate(intnum1,intnum2);}

2.3 Lambda表达式标准语法

2.3.1 完整语法结构

Lambda表达式固定结构:(参数列表) -> { 方法体代码 }

  • (参数列表):对应函数式接口抽象方法的参数列表,无参则空括号,多参逗号分隔;

  • ->:Lambda专属运算符(读作 goes to),固定写法,连接参数与方法体;

  • {}:方法体,对应抽象方法的具体实现逻辑。

2.3.2 Lambda五大语法特性(可省略规则)

Lambda的核心优势就是语法精简,满足条件可省略冗余代码,所有省略规则均为编译器自动推断

  1. 参数类型可省略:参数类型可全部省略,编译器根据接口抽象方法自动推断;

  2. 单参数括号可省略:参数列表仅有一个参数时,外层小括号可以省略;

  3. 无参数括号不可省:没有参数时,必须保留空括号;

  4. 单行方法体大括号可省略:方法体只有一行执行代码,可省略大括号与分号;

  5. 单行返回值可省略return:方法体仅有一行返回逻辑,可省略return关键字与大括号。

三、Lambda表达式完整实操与语法简化

基于上面自定义的三类函数式接口,从零演示完整写法与极简写法,全覆盖无参、单参、多参、无返回、有返回场景。

3.1 无参无返回值场景

publicclassLambdaDemo1{publicstaticvoidmain(String[]args){// 完整写法Actionaction1=()->{System.out.println("执行无参无返回Lambda逻辑");};action1.execute();// 极简写法(单行代码,省略大括号、分号)Actionaction2=()->System.out.println("极简无参Lambda执行");action2.execute();}}

3.2 单参数无返回值场景

publicclassLambdaDemo2{publicstaticvoidmain(String[]args){// 完整写法ConsumerTasktask1=(Stringmsg)->{System.out.println("接收参数:"+msg);};task1.accept("Java函数式编程");// 极简写法(省略参数类型、括号、大括号)ConsumerTasktask2=msg->System.out.println("极简接收参数:"+msg);task2.accept("Lambda表达式");}}

3.3 多参数有返回值场景

publicclassLambdaDemo3{publicstaticvoidmain(String[]args){// 完整写法ComputeTasktask1=(inta,intb)->{returna*b;};System.out.println("完整写法乘积:"+task1.calculate(6,8));// 极简写法(省略参数类型、return、大括号)ComputeTasktask2=(a,b)->a*b;System.out.println("极简写法乘积:"+task2.calculate(9,9));}}

四、方法引用(Lambda进阶简化)

当Lambda表达式的方法体仅仅是调用一个已存在的成熟方法,没有额外逻辑时,可以使用方法引用进一步简化代码,替代冗余的Lambda写法,让代码更加简洁优雅。

核心要求:被引用方法的参数列表、返回值类型必须与函数式接口抽象方法完全一致。

4.1 方法引用语法与分类

通用语法:方法归属者::方法名

  • 静态方法引用:类名::静态方法名

  • 实例方法引用:对象实例::普通方法名

4.2 实操案例

publicclassMethodRefDemo{// 静态方法:匹配双参数int返回值接口publicstaticintgetSum(intx,inty){returnx+y;}// 普通实例方法:匹配单参数无返回值接口publicvoidprintStr(Stringstr){System.out.println("打印内容:"+str);}publicstaticvoidmain(String[]args){// 1.静态方法引用(替代Lambda:(a,b) -> getSum(a,b))ComputeTasksumTask=MethodRefDemo::getSum;System.out.println("两数之和:"+sumTask.calculate(15,25));// 2.实例方法引用MethodRefDemodemo=newMethodRefDemo();ConsumerTaskprintTask=demo::printStr;printTask.accept("方法引用简化Lambda");}}

五、Lambda变量捕获(闭包特性)

5.1 闭包核心概念

闭包是指能够访问外部作用域变量的代码块。在Java中,Lambda表达式、匿名内部类都属于闭包实现,可以访问方法内的局部变量。

5.2 变量捕获规则

Lambda表达式访问外部局部变量时,变量会被隐式修饰为final,无需手动添加final关键字,但不允许二次赋值,否则编译报错。这也是Lambda闭包的核心特性:捕获的变量不可变

5.3 实操案例

publicclassLambdaClosureDemo{publicstaticvoidmain(String[]args){// 被Lambda捕获的局部变量,隐式finalStringtips="函数式编程闭包特性";intcount=10;Actionaction=()->{// 可以读取捕获的外部变量System.out.println("捕获变量:"+tips);System.out.println("计数常量:"+count);// 报错:变量不可二次赋值// count = 20;};action.execute();}}

六、JDK内置四大核心函数式接口

日常开发中无需频繁自定义函数式接口,JDK8 内置了大量通用函数式接口,其中四大核心接口覆盖90%的开发场景,是Stream流开发的基础。

6.1 Consumer消费型接口

核心特点:有参、无返回值,用于消费处理数据,核心方法void accept(T t)

常用场景:集合遍历、数据打印、数据消费处理。

importjava.util.ArrayList;importjava.util.List;importjava.util.function.Consumer;publicclassConsumerDemo{publicstaticvoidmain(String[]args){List<String>nameList=newArrayList<>();nameList.add("张三");nameList.add("李四");nameList.add("王五");// Lambda实现消费遍历Consumer<String>consumer=name->System.out.println("用户姓名:"+name);nameList.forEach(consumer);}}

6.2 Predicate断言型接口

核心特点:有参、返回布尔值,用于数据条件判断、过滤,核心方法boolean test(T t)

常用场景:集合过滤、条件筛选、数据校验。

importjava.util.ArrayList;importjava.util.List;importjava.util.function.Predicate;publicclassPredicateDemo{publicstaticvoidmain(String[]args){List<Integer>numList=newArrayList<>();numList.add(12);numList.add(25);numList.add(36);numList.add(48);// 筛选大于20的数字Predicate<Integer>predicate=num->num>20;numList.removeIf(predicate.negate());// 取反:删除不满足条件的System.out.println("筛选后数据:"+numList);}}

6.3 Function函数型接口

核心特点:有参、有返回值,用于数据类型转换、数据处理映射,核心方法R apply(T t)

常用场景:类型转换、数据加工、字段映射。

importjava.util.function.Function;publicclassFunctionDemo{publicstaticvoidmain(String[]args){// 字符串转整数Function<String,Integer>function=str->Integer.parseInt(str);Integernum=function.apply("666");System.out.println("转换后的数字:"+num);}}

6.4 Supplier供给型接口

核心特点:无参、有返回值,用于对外提供数据,核心方法T get()

常用场景:数据生成、对象创建、默认值供给。

importjava.util.function.Supplier;importjava.util.Random;publicclassSupplierDemo{publicstaticvoidmain(String[]args){// 随机生成100以内整数Supplier<Integer>supplier=()->newRandom().nextInt(100);System.out.println("随机数:"+supplier.get());}}

七、Stream流式编程详解

Stream流是JDK8基于Lambda表达式推出的集合数据处理工具,专门用于简化集合、数组的复杂数据操作,支持过滤、排序、映射、统计、去重、限制等链式操作,代码极简、可读性极强。

核心特性:Stream流不会修改原数据源,所有操作都会生成新的数据流,支持链式调用。

7.1 Stream流操作三阶段

  1. 获取流(创建阶段):通过集合、数组、静态方法生成Stream流;

  2. 中间操作(处理阶段):对流中数据进行过滤、排序、映射等处理,返回新流,可链式叠加;

  3. 终结操作(结果阶段):终止流操作,生成最终结果,执行后流关闭,不可复用。

7.2 Stream流常用中间操作

7.2.1 filter 数据过滤

基于Predicate接口,根据条件筛选数据,保留符合条件的元素。

importjava.util.ArrayList;importjava.util.List;importjava.util.stream.Collectors;publicclassStreamFilterDemo{publicstaticvoidmain(String[]args){List<String>fruitList=newArrayList<>();fruitList.add("苹果");fruitList.add("香蕉");fruitList.add("牛油果");fruitList.add("芒果");// 筛选名字长度为3的水果List<String>result=fruitList.stream().filter(fruit->fruit.length()==3).collect(Collectors.toList());System.out.println("筛选结果:"+result);}}

7.2.2 sorted 数据排序

支持自然排序、自定义排序,简化集合排序逻辑。

importjava.util.ArrayList;importjava.util.List;importjava.util.stream.Collectors;publicclassStreamSortDemo{publicstaticvoidmain(String[]args){List<Integer>numList=newArrayList<>();numList.add(22);numList.add(5);numList.add(89);numList.add(36);// 降序排序List<Integer>sortList=numList.stream().sorted((n1,n2)->n2-n1).collect(Collectors.toList());System.out.println("降序排序:"+sortList);}}

7.2.3 limit、skip 数据截取

limit(n):截取前n个元素;skip(n):跳过前n个元素,常用于分页场景。

importjava.util.ArrayList;importjava.util.List;publicclassStreamLimitDemo{publicstaticvoidmain(String[]args){List<Integer>numList=List.of(1,2,3,4,5,6,7,8,9,10);// 跳过前2个,截取3个元素numList.stream().skip(2).limit(3).forEach(System.out::println);}}

7.2.4 map 数据映射转换

基于Function接口,将流中元素转换为新的数据类型,实现数据加工。

importjava.util.List;importjava.util.stream.Collectors;publicclassStreamMapDemo{publicstaticvoidmain(String[]args){List<String>strList=List.of("10","20","30","40");// 字符串转整数,并翻倍List<Integer>intList=strList.stream().map(Integer::parseInt).map(num->num*2).collect(Collectors.toList());System.out.println("转换加工后:"+intList);}}

7.3 Stream常用终结操作

常用终结方法:forEach()遍历、collect()收集集合、count()统计数量、max/min()最值、anyMatch()匹配判断。

八、本章核心总结

  1. 函数式编程核心是将方法作为数据,Lambda表达式是Java函数式编程的核心语法;

  2. Lambda表达式必须依托函数式接口(单抽象方法接口)使用,@FunctionalInterface用于编译校验;

  3. Lambda语法支持多层精简,单行代码可省略括号、大括号、return等冗余语法;

  4. 方法引用是Lambda的进阶简化,用于直接调用已有成熟方法,代码更简洁;

  5. Lambda闭包会隐式固化外部局部变量,变量不可二次修改;

  6. JDK四大核心函数式接口:Consumer消费型、Predicate断言型、Function函数型、Supplier供给型;

  7. Stream流基于Lambda实现,通过创建、中间操作、终结操作三步,极简完成集合复杂数据处理,不修改原数据。

http://www.jsqmd.com/news/819565/

相关文章:

  • 孔子学院年度报告(2006-2024)缺2019
  • 罗博特科冲刺港股:年营收9.5亿同比降14% 市值一度超千亿 宁波科骏套现超6亿 高管李伟彬套现1230万
  • 旧版 Electron 应用如何迁移到新的 contextIsolation 安全策略
  • ARM调试断点寄存器DBGBVR_EL1原理与应用详解
  • DRV8871直流电机驱动板:从PWM调速到电流保护的实战指南
  • 如何在Swift中快速实现优雅的图片预览过渡动画:PreviewTransition完全指南 [特殊字符]
  • Nginx 1.30.1 发布:修复多个安全漏洞及连接缓存、响应传输等 Bug
  • AI智能体技能开发实战:基于MCP协议构建与集成外部工具
  • Backtrader终极指南:Python量化交易回测库的完整教程
  • 如何快速集成现代前端框架:Awesome Django前端开发完整指南 [特殊字符]
  • 从手忙脚乱到一键连招:用GSE重新定义你的魔兽世界战斗体验
  • yargs配置加密:敏感信息处理与解密中间件终极指南
  • Freewall深度解析:揭秘高性能网格布局引擎的实现原理
  • sxiv图像处理核心揭秘:缩放、旋转和伽马校正的代码实现
  • Python 3.12 Std_Libs - String - 06 - 前缀和后缀
  • RepoDB类处理器高级用法:实现复杂业务逻辑的优雅解决方案
  • React Native Navigation终极升级指南:从旧版本平滑迁移到最新版本的10个关键步骤 [特殊字符]
  • 71.人工智能实战:RAG 权限过滤怎么做?从前期发现“越权召回”到文档 ACL、检索过滤与引用权限校验
  • 嵌入式开发中CircuitPython单精度浮点数精度解析与优化策略
  • 终极指南:如何用apt-offline在无网环境下管理Debian软件包
  • 如何用AML模组管理器打造专属XCOM游戏体验:新手完整指南
  • 【Midjourney商业设计变现指南】:20个已验证的高转化落地场景与客户签约话术库
  • AI编程伙伴Cursor高效使用指南:从提示词工程到实战工作流
  • 用 RSUSR040 评估 SAP 授权对象,让权限治理从经验判断走向可检索、可复核、可审计
  • 全网最全的彩虹云商城系统源码以及各类发卡网源码,绝对精品
  • 如何利用AKShare金融数据接口探索量子计算在投资分析中的应用前景
  • PearProject性能优化技巧:让你的协作系统运行更加流畅
  • 突破性解决方案:Noto Emoji如何彻底终结表情符号乱码问题
  • 从 SUIM 到 ABAP 代码,重新理解 SAP 授权评估里的 RSUSR030
  • 【空间计算】【复杂系统】运动几何及运动测量