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

Java — Lambda 表达式与函数式接口解析

在 Java 8 引入 Lambda 表达式函数式接口 之后,Java 语言在简洁性与表达力上有了质的提升。本文将逐步讲解相关的核心知识点,包括 函数式接口定义、Lambda 使用、方法引用 以及 常见函数式接口


一、函数式接口(Functional Interface)

定义:接口中只允许存在一个抽象方法(可以有多个 defaultstatic 方法),这样的接口就可以作为 Lambda 表达式 的目标类型。

示例:

@FunctionalInterface
interface MyInterface {int sum(int i, int j);
}

这里的 MyInterface 只有一个抽象方法 sum,因此是一个函数式接口。
Java 提供了 @FunctionalInterface 注解来保证语义明确,编译器会强制检查该接口是否满足“只有一个抽象方法”的条件。

还可以有 default 方法:

@FunctionalInterface
interface MyInterface1 {int haha();default int hello() {return 2;}
}

即便 hellodefaulthaha 仍然是唯一抽象方法,所以依然是函数式接口。


二、Lambda 表达式的语法与应用

Lambda 表达式本质上是对 匿名类 的简化,它能让代码更简洁、可读性更强。

示例:

MyInterface myInterface = (i, j) -> i + j;
System.out.println(myInterface.sum(1, 2)); // 输出 3

对应的传统写法需要创建一个匿名类:

MyInterface myInterface = new MyInterface() {@Overridepublic int sum(int i, int j) {return i + j;}
};

Lambda 大幅简化了开发。


三、方法引用(Method Reference)

Lambda 有时只是调用已有方法,可以进一步简化为 方法引用

示例:

Collections.sort(list, String::compareTo);

等价于:

Collections.sort(list, (s1, s2) -> s1.compareTo(s2));

方法引用有四类:

  1. 类名::静态方法
  2. 对象::实例方法
  3. 类名::实例方法
  4. 类名::new(构造器引用)

四、常见函数式接口

java.util.function 包预定义了大量常用函数式接口。

1. Consumer<T> / BiConsumer<T, U> —— 有入参,无返回值

BiConsumer<String, String> consumer = (a, b) -> System.out.println(a + b);
consumer.accept("Hello ", "World");

2. Function<T, R> / BiFunction<T, U, R> —— 有入参,有返回值

Function<String, Integer> function = s -> s.length();
System.out.println(function.apply("Hello World"));  // 11BiFunction<String, Integer, Integer> biFunction = (s, i) -> s.substring(i).length();
System.out.println(biFunction.apply("Hello World, Mario", 5));

3. Supplier<T> —— 无入参,有返回值

Supplier<String> supplier = () -> UUID.randomUUID().toString();
System.out.println(supplier.get());

4. Runnable —— 无入参,无返回值

Runnable runnable = () -> System.out.println("Hello World");
new Thread(runnable).start();

5. Predicate<T> —— 断言型接口(返回 boolean

Predicate<Integer> even = i -> i % 2 == 0;
System.out.println(even.test(2));            // true
System.out.println(even.negate().test(2));   // false

这里的 negate() 会返回一个新的 Predicate,逻辑是:

(t) -> !even.test(t)

下面用一个例子来展示如何使用 Supplier(供给者)、Predicate(断言)、Function(转换器)、Consumer(消费者) 这四类核心接口,并将它们自然地串联在一起,构建一条“数据处理流水线”。

在这里插入图片描述

private static void myMethod(Predicate<String> isNumber,Supplier<String> supplier,Consumer<Integer> consumer,Function<String, Integer> change) {if (isNumber.test(supplier.get())) {consumer.accept(change.apply(supplier.get()));} else {System.out.println("not a number");}
}

流程可以分解为:

  1. Supplier 负责“提供数据”
  2. Predicate 验证数据是否合法(是否为数字)
  3. Function 将字符串转换为整数 Integer
  4. Consumer 消费结果

这就是一种典型的 函数组合 思路。完整代码如下:

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;public class FunctionDemo {public static void main(String[] args) {// 1. 定义数据提供者函数Supplier<String> supplier = () -> "47";// 2. 断言:验证是否为数字Predicate<String> isNumber = str -> str.matches("-?\\d+(\\.\\d+)?");// 3. Function转换器:把字符串变成数字Function<String, Integer> change = str -> Integer.parseInt(str);// 4. 消费者:打印数字Consumer<Integer> consumer = integer -> {if (integer % 2 == 0) System.out.println("even: " + integer);else System.out.println("odd: " + integer);};// 第一次调用myMethod(isNumber, supplier, consumer, change);// 使用 Lambda 与方法引用直接传参myMethod(str -> str.matches("-?\\d+(\\.\\d+)?"),() -> "777",integer -> {if (integer % 2 == 0) System.out.println("even: " + integer);else System.out.println("odd: " + integer);},Integer::parseInt);}private static void myMethod(Predicate<String> isNumber,Supplier<String> supplier,Consumer<Integer> consumer,Function<String, Integer> change) {// 将上述函数串在一起,判断42的奇偶性if (isNumber.test(supplier.get())) {consumer.accept(change.apply(supplier.get()));} else {System.out.println("not a number");}}
}

程序输出为:

odd: 47
odd: 777

五、测试程序(仅为练习使用)

import java.util.ArrayList;
import java.util.Collections;
import java.util.UUID;
import java.util.function.*;// 函数式接口:接口中只有一个(有且仅有一个)未实现的方法,这个接口就叫函数式接口,只要是函数式接口就可以用Lambda表达式简化
interface MyInterface {int sum(int i, int j);
}// 这个接口也符合有且仅有一个未实现的方法 这个标准,因此也是函数式接口
// 如果以后检查某个接口是否为函数式接口,可以用 @FunctionalInterface 注解
// 如果没有报错,说明是函数式接口
@FunctionalInterface
interface MyInterface1 {int haha();default int hello() {return 2;}
}public class Lambda {public static void main(String[] args) {MyInterface myInterface = (i, j) -> i + j;System.out.println(myInterface.sum(1, 2));MyInterface1 myInterface1 = () -> 1;System.out.println(myInterface1.haha());var list = new ArrayList<String>();list.add("Alice");list.add("Bob");list.add("Charlie");list.add("David");Collections.sort(list, (s1, s2) -> s2.compareTo(s1));System.out.println(list);// 类::方法  引用类中的实例方法(或静态方法);忽略lambda的完整写法Collections.sort(list, String::compareTo);System.out.println(list);//        new Thread(() -> System.out.println("Hello World")).start();// 1. 有入参,无出参BiConsumer<String, String> consumer = (a, b) -> System.out.println(a + b);consumer.accept("Hello ", "World");// 2. 有入参,有出参Function<String, Integer> function = s -> s.length();System.out.println(function.apply("Hello World"));BiFunction<String, Integer, Integer> biFunction = (s, i) -> s.substring(i).length();System.out.println(biFunction.apply("Hello World, Mario", 5));// 3. 无入参,无出参Runnable runnable = () -> System.out.println("Hello World");new Thread(runnable).start();// 4. 无入参,有出参Supplier<String> supplier = () -> UUID.randomUUID().toString();System.out.println(supplier.get());// 断言Predicate<Integer> even = i -> i % 2 == 0;System.out.println(even.test(2));  // 正向判断System.out.println(even.negate().test(2));  // 反向判断/**even.negate()even 是 i -> i % 2 == 0negate() 会返回一个新的 Predicate:(t) -> !even.test(t).test(2)调用这个新的 Predicate 的 test(2)它内部会先调用 even.test(2) → 结果是 true再取反 → false*/}
}

程序运行结果为:

3
1
[David, Charlie, Bob, Alice]
[Alice, Bob, Charlie, David]
Hello World
11
13
Hello World
8209a7dd-8a1e-4c2e-bf1b-669fedda6b46
true
false

六、总结

  1. 函数式接口 是 Lambda 的基础,一个接口只能有一个抽象方法。
  2. Lambda 表达式 极大简化了匿名类写法,使 Java 更接近函数式编程。
  3. 方法引用 可以在 Lambda 仅仅调用现有方法时使用,更加简洁。
  4. Java 8 内置的 ConsumerFunctionSupplierPredicate 等接口满足了大多数常见场景。

得益于 Lambda 与函数式接口,Java 在流式 API(Stream API)、并发编程、事件驱动开发等领域变得更强大、更现代化。


文章转载自:

http://imyw6Bis.qgwdc.cn
http://iPwSnyIm.qgwdc.cn
http://TIsxcbD8.qgwdc.cn
http://ckc3mPCt.qgwdc.cn
http://LGIQagjG.qgwdc.cn
http://OxNWXnaE.qgwdc.cn
http://nWDXAY86.qgwdc.cn
http://EQzApZ9i.qgwdc.cn
http://ojksytq0.qgwdc.cn
http://UtMNJIQN.qgwdc.cn
http://sdJLN5vU.qgwdc.cn
http://u1GcFZDf.qgwdc.cn
http://hmSccIEZ.qgwdc.cn
http://4nLWZRmT.qgwdc.cn
http://W10boIlm.qgwdc.cn
http://O4ZYiP3Q.qgwdc.cn
http://jwzFBrvv.qgwdc.cn
http://FblqD3RG.qgwdc.cn
http://39nADdYg.qgwdc.cn
http://betxnHbq.qgwdc.cn
http://LCywvgem.qgwdc.cn
http://F0NmDj3v.qgwdc.cn
http://8HymXsz5.qgwdc.cn
http://RVXZ2CLm.qgwdc.cn
http://yfaZdyZW.qgwdc.cn
http://ySDAj1K6.qgwdc.cn
http://0puDltuc.qgwdc.cn
http://1s8sGPg7.qgwdc.cn
http://YxFIkH4E.qgwdc.cn
http://WocvDLsl.qgwdc.cn
http://www.dtcms.com/a/377015.html

相关文章:

  • Apache Commons Math3 使用指南:强大的Java数学库
  • 数据结构中的 二叉树
  • SoC分区
  • 先买实现烦过
  • Qt C++ 图形绘制完全指南:从基础到进阶实战
  • 我在嘉顺达蓝海的安全坚守
  • fastadmin安装后后台提示putenv()报错,不显示验证码
  • macOS苹果电脑运行向日葵远程控制软件闪退
  • 平衡车 -- 倒立摆
  • 利用OpenCV实现模板与多个对象匹配
  • 机器学习的发展与应用:从理论到现实
  • 软考系统架构设计师之软件系统建模
  • leedcode 算法刷题第三十一天
  • IDEA下载安装图文教程(非常详细,适合新手)
  • Spark 性能优化全攻略:内存管理、shuffle 优化与参数调优
  • 老味道私房菜订餐系统的设计与实现(代码+数据库+LW)
  • 古董装载优化:30秒破解重量限制
  • Vue2手录02-指令
  • 爬虫逆向之瑞数6案例(深圳大学某某附属医院)
  • AWK工具使用与技巧指南
  • Java程序员职业发展路径与转型选择分析报告(2025年)
  • 资产管理软件哪家口碑好
  • 【实战中提升自己完结篇】分支篇之分支之无线、内网安全与QOS部署(完结)
  • 【Qt】PyQt、原生QT、PySide6三者的多方面比较
  • 多级缓存架构
  • 多模态对齐与多模态融合
  • 【MySQL】常用SQL语句
  • 教师节组诗-我不少年师已老,无报师恩仅遥忆
  • 手把手带你推导“逻辑回归”核心公式
  • 当按摩机器人“活了”:Deepoc具身智能如何重新定义人机交互体验