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 自定义函数式接口案例
// 无参无返回值函数式接口
@FunctionalInterface
public interface Action {
void execute();
}
// 单参数无返回值函数式接口
@FunctionalInterface
public interface ConsumerTask {
void accept(String content);
}
// 多参数有返回值函数式接口
@FunctionalInterface
public interface ComputeTask {
int calculate(int num1, int num2);
}
2.3 Lambda表达式标准语法
2.3.1 完整语法结构
Lambda表达式固定结构:(参数列表) -> { 方法体代码 }
-
(参数列表):对应函数式接口抽象方法的参数列表,无参则空括号,多参逗号分隔;
-
->:Lambda专属运算符(读作 goes to),固定写法,连接参数与方法体;
-
{}:方法体,对应抽象方法的具体实现逻辑。
2.3.2 Lambda五大语法特性(可省略规则)
Lambda的核心优势就是语法精简,满足条件可省略冗余代码,所有省略规则均为编译器自动推断:
-
参数类型可省略:参数类型可全部省略,编译器根据接口抽象方法自动推断;
-
单参数括号可省略:参数列表仅有一个参数时,外层小括号可以省略;
-
无参数括号不可省:没有参数时,必须保留空括号;
-
单行方法体大括号可省略:方法体只有一行执行代码,可省略大括号与分号;
-
单行返回值可省略return:方法体仅有一行返回逻辑,可省略return关键字与大括号。
三、Lambda表达式完整实操与语法简化
基于上面自定义的三类函数式接口,从零演示完整写法与极简写法,全覆盖无参、单参、多参、无返回、有返回场景。
3.1 无参无返回值场景
public class LambdaDemo1 {
public static void main(String[] args) {
// 完整写法
Action action1 = () -> {
System.out.println("执行无参无返回Lambda逻辑");
};
action1.execute();
// 极简写法(单行代码,省略大括号、分号)
Action action2 = () -> System.out.println("极简无参Lambda执行");
action2.execute();
}
}
3.2 单参数无返回值场景
public class LambdaDemo2 {
public static void main(String[] args) {
// 完整写法
ConsumerTask task1 = (String msg) -> {
System.out.println("接收参数:" + msg);
};
task1.accept("Java函数式编程");
// 极简写法(省略参数类型、括号、大括号)
ConsumerTask task2 = msg -> System.out.println("极简接收参数:" + msg);
task2.accept("Lambda表达式");
}
}
3.3 多参数有返回值场景
public class LambdaDemo3 {
public static void main(String[] args) {
// 完整写法
ComputeTask task1 = (int a, int b) -> {
return a * b;
};
System.out.println("完整写法乘积:" + task1.calculate(6, 8));
// 极简写法(省略参数类型、return、大括号)
ComputeTask task2 = (a, b) -> a * b;
System.out.println("极简写法乘积:" + task2.calculate(9, 9));
}
}
四、方法引用(Lambda进阶简化)
当Lambda表达式的方法体仅仅是调用一个已存在的成熟方法,没有额外逻辑时,可以使用方法引用进一步简化代码,替代冗余的Lambda写法,让代码更加简洁优雅。
核心要求:被引用方法的参数列表、返回值类型必须与函数式接口抽象方法完全一致。
4.1 方法引用语法与分类
通用语法:方法归属者::方法名
-
静态方法引用:类名::静态方法名
-
实例方法引用:对象实例::普通方法名
4.2 实操案例
public class MethodRefDemo {
// 静态方法:匹配双参数int返回值接口
public static int getSum(int x, int y) {
return x + y;
}
// 普通实例方法:匹配单参数无返回值接口
public void printStr(String str) {
System.out.println("打印内容:" + str);
}
public static void main(String[] args) {
// 1.静态方法引用(替代Lambda:(a,b) -> getSum(a,b))
ComputeTask sumTask = MethodRefDemo::getSum;
System.out.println("两数之和:" + sumTask.calculate(15, 25));
// 2.实例方法引用
MethodRefDemo demo = new MethodRefDemo();
ConsumerTask printTask = demo::printStr;
printTask.accept("方法引用简化Lambda");
}
}
五、Lambda变量捕获(闭包特性)
5.1 闭包核心概念
闭包是指能够访问外部作用域变量的代码块。在Java中,Lambda表达式、匿名内部类都属于闭包实现,可以访问方法内的局部变量。
5.2 变量捕获规则
Lambda表达式访问外部局部变量时,变量会被隐式修饰为final,无需手动添加final关键字,但不允许二次赋值,否则编译报错。这也是Lambda闭包的核心特性:捕获的变量不可变。
5.3 实操案例
public class LambdaClosureDemo {
public static void main(String[] args) {
// 被Lambda捕获的局部变量,隐式final
String tips = "函数式编程闭包特性";
int count = 10;
Action action = () -> {
// 可以读取捕获的外部变量
System.out.println("捕获变量:" + tips);
System.out.println("计数常量:" + count);
// 报错:变量不可二次赋值
// count = 20;
};
action.execute();
}
}
六、JDK内置四大核心函数式接口
日常开发中无需频繁自定义函数式接口,JDK8 内置了大量通用函数式接口,其中四大核心接口覆盖90%的开发场景,是Stream流开发的基础。
6.1 Consumer消费型接口
核心特点:有参、无返回值,用于消费处理数据,核心方法 void accept(T t)。
常用场景:集合遍历、数据打印、数据消费处理。
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class ConsumerDemo {
public static void main(String[] args) {
List<String> nameList = new ArrayList<>();
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)。
常用场景:集合过滤、条件筛选、数据校验。
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class PredicateDemo {
public static void main(String[] args) {
List<Integer> numList = new ArrayList<>();
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)。
常用场景:类型转换、数据加工、字段映射。
import java.util.function.Function;
public class FunctionDemo {
public static void main(String[] args) {
// 字符串转整数
Function<String, Integer> function = str -> Integer.parseInt(str);
Integer num = function.apply("666");
System.out.println("转换后的数字:" + num);
}
}
6.4 Supplier供给型接口
核心特点:无参、有返回值,用于对外提供数据,核心方法 T get()。
常用场景:数据生成、对象创建、默认值供给。
import java.util.function.Supplier;
import java.util.Random;
public class SupplierDemo {
public static void main(String[] args) {
// 随机生成100以内整数
Supplier<Integer> supplier = () -> new Random().nextInt(100);
System.out.println("随机数:" + supplier.get());
}
}
七、Stream流式编程详解
Stream流是JDK8基于Lambda表达式推出的集合数据处理工具,专门用于简化集合、数组的复杂数据操作,支持过滤、排序、映射、统计、去重、限制等链式操作,代码极简、可读性极强。
核心特性:Stream流不会修改原数据源,所有操作都会生成新的数据流,支持链式调用。
7.1 Stream流操作三阶段
-
获取流(创建阶段):通过集合、数组、静态方法生成Stream流;
-
中间操作(处理阶段):对流中数据进行过滤、排序、映射等处理,返回新流,可链式叠加;
-
终结操作(结果阶段):终止流操作,生成最终结果,执行后流关闭,不可复用。
7.2 Stream流常用中间操作
7.2.1 filter 数据过滤
基于Predicate接口,根据条件筛选数据,保留符合条件的元素。
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class StreamFilterDemo {
public static void main(String[] args) {
List<String> fruitList = new ArrayList<>();
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 数据排序
支持自然排序、自定义排序,简化集合排序逻辑。
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class StreamSortDemo {
public static void main(String[] args) {
List<Integer> numList = new ArrayList<>();
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个元素,常用于分页场景。
import java.util.ArrayList;
import java.util.List;
public class StreamLimitDemo {
public static void main(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接口,将流中元素转换为新的数据类型,实现数据加工。
import java.util.List;
import java.util.stream.Collectors;
public class StreamMapDemo {
public static void main(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()匹配判断。
八、本章核心总结
-
函数式编程核心是将方法作为数据,Lambda表达式是Java函数式编程的核心语法;
-
Lambda表达式必须依托函数式接口(单抽象方法接口)使用,@FunctionalInterface用于编译校验;
-
Lambda语法支持多层精简,单行代码可省略括号、大括号、return等冗余语法;
-
方法引用是Lambda的进阶简化,用于直接调用已有成熟方法,代码更简洁;
-
Lambda闭包会隐式固化外部局部变量,变量不可二次修改;
-
JDK四大核心函数式接口:Consumer消费型、Predicate断言型、Function函数型、Supplier供给型;
-
Stream流基于Lambda实现,通过创建、中间操作、终结操作三步,极简完成集合复杂数据处理,不修改原数据。
更多推荐



所有评论(0)