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的核心优势就是语法精简满足条件可省略冗余代码所有省略规则均为编译器自动推断参数类型可省略参数类型可全部省略编译器根据接口抽象方法自动推断单参数括号可省略参数列表仅有一个参数时外层小括号可以省略无参数括号不可省没有参数时必须保留空括号单行方法体大括号可省略方法体只有一行执行代码可省略大括号与分号单行返回值可省略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函数式编程);// 极简写法省略参数类型、括号、大括号ConsumerTasktask2msg-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){returnxy;}// 普通实例方法匹配单参数无返回值接口publicvoidprintStr(Stringstr){System.out.println(打印内容str);}publicstaticvoidmain(String[]args){// 1.静态方法引用替代Lambda(a,b) - getSum(a,b)ComputeTasksumTaskMethodRefDemo::getSum;System.out.println(两数之和sumTask.calculate(15,25));// 2.实例方法引用MethodRefDemodemonewMethodRefDemo();ConsumerTaskprintTaskdemo::printStr;printTask.accept(方法引用简化Lambda);}}五、Lambda变量捕获闭包特性5.1 闭包核心概念闭包是指能够访问外部作用域变量的代码块。在Java中Lambda表达式、匿名内部类都属于闭包实现可以访问方法内的局部变量。5.2 变量捕获规则Lambda表达式访问外部局部变量时变量会被隐式修饰为final无需手动添加final关键字但不允许二次赋值否则编译报错。这也是Lambda闭包的核心特性捕获的变量不可变。5.3 实操案例publicclassLambdaClosureDemo{publicstaticvoidmain(String[]args){// 被Lambda捕获的局部变量隐式finalStringtips函数式编程闭包特性;intcount10;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){ListStringnameListnewArrayList();nameList.add(张三);nameList.add(李四);nameList.add(王五);// Lambda实现消费遍历ConsumerStringconsumername-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){ListIntegernumListnewArrayList();numList.add(12);numList.add(25);numList.add(36);numList.add(48);// 筛选大于20的数字PredicateIntegerpredicatenum-num20;numList.removeIf(predicate.negate());// 取反删除不满足条件的System.out.println(筛选后数据numList);}}6.3 Function函数型接口核心特点有参、有返回值用于数据类型转换、数据处理映射核心方法R apply(T t)。常用场景类型转换、数据加工、字段映射。importjava.util.function.Function;publicclassFunctionDemo{publicstaticvoidmain(String[]args){// 字符串转整数FunctionString,Integerfunctionstr-Integer.parseInt(str);Integernumfunction.apply(666);System.out.println(转换后的数字num);}}6.4 Supplier供给型接口核心特点无参、有返回值用于对外提供数据核心方法T get()。常用场景数据生成、对象创建、默认值供给。importjava.util.function.Supplier;importjava.util.Random;publicclassSupplierDemo{publicstaticvoidmain(String[]args){// 随机生成100以内整数SupplierIntegersupplier()-newRandom().nextInt(100);System.out.println(随机数supplier.get());}}七、Stream流式编程详解Stream流是JDK8基于Lambda表达式推出的集合数据处理工具专门用于简化集合、数组的复杂数据操作支持过滤、排序、映射、统计、去重、限制等链式操作代码极简、可读性极强。核心特性Stream流不会修改原数据源所有操作都会生成新的数据流支持链式调用。7.1 Stream流操作三阶段获取流创建阶段通过集合、数组、静态方法生成Stream流中间操作处理阶段对流中数据进行过滤、排序、映射等处理返回新流可链式叠加终结操作结果阶段终止流操作生成最终结果执行后流关闭不可复用。7.2 Stream流常用中间操作7.2.1 filter 数据过滤基于Predicate接口根据条件筛选数据保留符合条件的元素。importjava.util.ArrayList;importjava.util.List;importjava.util.stream.Collectors;publicclassStreamFilterDemo{publicstaticvoidmain(String[]args){ListStringfruitListnewArrayList();fruitList.add(苹果);fruitList.add(香蕉);fruitList.add(牛油果);fruitList.add(芒果);// 筛选名字长度为3的水果ListStringresultfruitList.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){ListIntegernumListnewArrayList();numList.add(22);numList.add(5);numList.add(89);numList.add(36);// 降序排序ListIntegersortListnumList.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){ListIntegernumListList.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){ListStringstrListList.of(10,20,30,40);// 字符串转整数并翻倍ListIntegerintListstrList.stream().map(Integer::parseInt).map(num-num*2).collect(Collectors.toList());System.out.println(转换加工后intList);}}7.3 Stream常用终结操作常用终结方法forEach()遍历、collect()收集集合、count()统计数量、max/min()最值、anyMatch()匹配判断。八、本章核心总结函数式编程核心是将方法作为数据Lambda表达式是Java函数式编程的核心语法Lambda表达式必须依托函数式接口单抽象方法接口使用FunctionalInterface用于编译校验Lambda语法支持多层精简单行代码可省略括号、大括号、return等冗余语法方法引用是Lambda的进阶简化用于直接调用已有成熟方法代码更简洁Lambda闭包会隐式固化外部局部变量变量不可二次修改JDK四大核心函数式接口Consumer消费型、Predicate断言型、Function函数型、Supplier供给型Stream流基于Lambda实现通过创建、中间操作、终结操作三步极简完成集合复杂数据处理不修改原数据。