【Java 新特性】常用函数式接口

在现代 Java 开发中,函数式接口无疑是一种强大的工具。它们不仅让代码更简洁,也使开发者能够更灵活地表达逻辑。函数式接口就像电器的插头,为你的代码提供了“标准接口”。想象一下,有了插头,不同的设备都能轻松接入电源。同样,函数式接口让你可以用统一的方式编写逻辑,无论是数据处理、条件判断还是结果生成,都变得更灵活、更简洁。


一、什么是函数式接口?

函数式接口是 仅包含一个抽象方法 的接口。它们是 Java 8 中引入的核心特性,常与 Lambda 表达式 一起使用。Java 提供了 @FunctionalInterface 注解来显式声明一个接口为函数式接口,同时也让编译器帮助我们验证其规范性。

关于 Lambda 表达式的详细讲解可以参考我的另一篇博客

函数式接口的基本规则:

  1. 必须只有一个抽象方法
  2. 可以包含多个默认方法或静态方法。
  3. 使用 @FunctionalInterface 注解并非强制,但推荐使用。

形象比喻

函数式接口就像一张定制的契约(合同),规定只有一个核心任务需要实现。例如,Runnable 的任务是 "做某件事情",具体做什么由你定义,而 Java 会帮你安排如何调用。

定义示例

// 此自定义函数式接口接收两个参数,返回一个 int 类型的值
@FunctionalInterface
interface Calculator {
    int calculate(int a, int b);
}

实现时:

Calculator addition = (a, b) -> a + b;
System.out.println(addition.calculate(5, 3)); // 输出:8

二、为什么需要函数式接口?

在 Java 8 之前,我们实现逻辑常需要匿名内部类,这既冗长又不直观。函数式接口加上 Lambda 表达式,简直就是如虎添翼。

对比代码:

  • 匿名内部类写法
Runnable task = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello, World!");
    }
};
  • Lambda 表达式写法
Runnable task = () -> System.out.println("Hello, World!");

是不是清爽简洁多了?


三、常用的函数式接口

Java 提供了一整套常用的函数式接口,它们就像工具箱中的各种工具,针对不同任务有不同功能。

接口方法签名用途例子类比
Function<T,R>R apply(T t)将一个参数映射为另一个结果就像去买东西,一手交钱(T)一手交货(R)
Consumer<T>void accept(T t)消费一个参数,无返回值就像吃食物(T),吃完就消化了(void)。
Supplier<T>T get()无参数,返回一个结果就像一台免费物品供应机,按下按钮给你物品(T)。
Predicate<T>boolean test(T t)判断条件,返回布尔值就像一台安检机,判断物品(T)是否符合安全标准(boolean 类型)。
BiFunction<T,U,R>R apply(T t, U u)接收两个参数,返回一个结果就像输入两个不同类型的值(T、U),输出操作后的任意结果(R)。
BiConsumer<T,U>void accept(T t, U u)接收两个参数,无返回值两个不同类型的值(T、U)进行操作,不返回结果
UnaryOperator<T>T apply(T t)一元操作,输入和输出类型相同对一个值进行操作,输入(T)和输出(T)的类型没变
BinaryOperator<T>T apply(T t1, T t2)二元操作,输入和输出类型相同两个相同类型的值进行操作,返回操作后相同类型的结果(T)。

四、函数式接口基础用法

1. Function:将输入映射为输出

Function<String, Integer> stringToLength = s -> s.length();
System.out.println(stringToLength.apply("Hello")); // 输出:5

2. Predicate:判断条件是否成立

Predicate<Integer> isEven = n -> n % 2 == 0;
System.out.println(isEven.test(4)); // 输出:true
System.out.println(isEven.test(3)); // 输出:false

3. Supplier:无条件生成结果

Supplier<Double> randomSupplier = () -> Math.random();
System.out.println(randomSupplier.get());

4. Consumer:处理输入,不返回结果

Consumer<String> logger = message -> System.out.println("Log: " + message);
logger.accept("Application started"); // 输出:Log: Application started

5. UnaryOperator:对输入进行一元操作

UnaryOperator<Integer> increment = n -> n + 1;
System.out.println(increment.apply(5)); // 输出:6

6. BinaryOperator:对两个输入进行二元操作

BinaryOperator<Integer> max = (a, b) -> a > b ? a : b;
System.out.println(max.apply(5, 10)); // 输出:10

五、开发中常用场景

1. 使用 Function 进行 map 转换

List<Integer> integersList = List.of(1, 2, 3);
List<Integer> mapList = integersList.stream()
    .map(i -> (i * 2))
    .toList();

2. 使用 Function 实现多步转换

就像流水线上的加工流程,一个任务接着另一个任务:

Function<Integer, Integer> multiplyBy2 = x -> x * 2;
Function<Integer, Integer> add3 = x -> x + 3;

Function<Integer, Integer> combined = multiplyBy2.andThen(add3);
System.out.println(combined.apply(5)); // 输出:13

3. 使用 Predicate 实现复杂条件判断

类比:安检门,多个条件逐步筛选。

Predicate<String> startsWithA = s -> s.startsWith("A");
Predicate<String> endsWithZ = s -> s.endsWith("Z");

Predicate<String> complexCondition = startsWithA.and(endsWithZ);

System.out.println(complexCondition.test("AZ")); // 输出:true
System.out.println(complexCondition.test("BZ")); // 输出:false

4. 使用 Predicate 进行过滤

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream()
     .filter(name -> name.startsWith("A"))
     .forEach(System.out::println); // 输出:Alice

5. 使用 Supplier 延迟加载资源

Supplier<String> configSupplier = () -> {
    System.out.println("Fetching configuration...");
    return "Default Config";
};

// 只有在调用 get() 时才会执行逻辑
System.out.println(configSupplier.get()); // 输出:Fetching configuration...

6. 使用 Consumer 记录日志

专注于记录,但不返回结果。

Consumer<String> logger = message -> System.out.println("Log: " + message);
logger.accept("User logged in"); // 输出:Log: User logged in

7. 使用 BiConsumer 处理键值对

BiConsumer<String, Integer> printOrder = (item, quantity) -> 
    System.out.println("Ordered " + quantity + "x " + item);

printOrder.accept("Apple", 3); // 输出:Ordered 3x Apple

8. 使用 UnaryOperator 实现批量自增

每个商品都增加同样的数量。

UnaryOperator<Integer> incrementBy10 = x -> x + 10;
List<Integer> numbers = List.of(1, 2, 3, 4);
List<Integer> incrementedNumbers = numbers.stream()
    .map(incrementBy10)
    .toList();

System.out.println(incrementedNumbers); // 输出:[11, 12, 13, 14]

9. 使用 BinaryOperator 处理累积运算(聚合数据)

像汇总账单,每次合并两个部分,直到得出总数。

BinaryOperator<Integer> sumOperator = (a, b) -> a + b;
List<Integer> nums = List.of(1, 2, 3, 4, 5);
int total = nums.stream()
    .reduce(0, sumOperator);

System.out.println(total); // 输出:15

六、总结

函数式接口让代码更简洁、更灵活,不再是过去冗长的匿名类实现。通过以下这张表格,你可以快速回忆常用的几个函数式接口的用途:

接口方法签名主要用途
Function<T,R>R apply(T t)接受一个输入,返回一个输出,常用于映射操作
Consumer<T>void accept(T t)消费输入,无返回值,常用于执行操作
Supplier<T>T get()无输入,生成结果,常用于延迟加载
Predicate<T>boolean test(T t)判断条件,返回布尔值,用于过滤操作
UnaryOperator<T>T apply(T t)对输入执行一元操作,返回同类型结果
BinaryOperator<T>T apply(T t1, T t2)对两个输入执行二元操作,返回同类型结果
BiFunction<T,U,R>R apply(T t, U u)接收两个不同类型输入,返回一个输出
BiConsumer<T,U>void accept(T t, U u)消费两个不同类型输入,无返回值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/945861.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构与算法之动态规划: LeetCode 337. 打家劫舍 III (Ts版)

打家劫舍 III https://leetcode.cn/problems/house-robber-iii/description/ 描述 小偷又发现了一个新的可行窃的地区。这个地区只有一个入口&#xff0c;我们称之为 root除了 root 之外&#xff0c;每栋房子有且只有一个“父“房子与之相连一番侦察之后&#xff0c;聪明的小…

chatwoot 开源客服系统搭建

1. 准备开源客服系统&#xff08;我是用的Chatwoot &#xff09; 可以选择以下开源客服系统作为基础&#xff1a; Chatwoot: 功能强大&#xff0c;支持多渠道客户对接&#xff0c;&#xff08;支持app&#xff0c;web&#xff09;。Zammad: 现代的开源工单系统。FreeScout: 免…

sentinel-请求限流、线程隔离、本地回调、熔断

请求限流&#xff1a;控制QPS来达到限流的目的 线程隔离&#xff1a;控制线程数量来达到限流的目录 本地回调&#xff1a;当线程被限流、隔离、熔断之后、就不会发起远程调用、而是使用本地已经准备好的回调去提醒用户 服务熔断&#xff1a;熔断也叫断路器&#xff0c;当失败、…

鸿蒙开发-ArkTS中使用Path组件

在ArkTS中使用Path组件&#xff0c;可以按照以下步骤进行&#xff1a; 一、了解Path组件 Path组件用于根据绘制路径生成封闭的自定义形状。该组件从API Version 7开始支持&#xff0c;并随着后续版本的更新可能增加新的功能。Path组件支持多种属性和方法&#xff0c;用于定义…

高效管理 Nginx 的利器:nginxWebUI 指南和 Docker 部署安装过程

前言 Nginx WebUI 是一个为 Nginx 提供图形化管理界面的工具。通过 WebUI&#xff0c;用户可以轻松管理 Nginx 配置&#xff0c;而无需直接编辑配置文件&#xff0c;尤其适合新手用户和频繁修改配置的场景。 官网文档&#xff1a;nginxWebUI - 文档 本文将分享为什么选择 ngin…

Linux网络 | 理解Web路径 以及 实现一个简单的helloworld网页

前言&#xff1a;本节内容承接上节课的http相关的概念&#xff0c; 主要是实现一个简单的接收http协议请求的服务。这个程序对于我们理解后面的http协议的格式&#xff0c;报头以及网络上的资源的理解&#xff0c; 以及本节web路径等等都有着重要作用。 可以说我们就用代码来理…

2.5万字 - 用TensorFlow和PyTorch分别实现五种经典模型

在深度学习领域&#xff0c;TensorFlow和PyTorch是两大广泛使用的框架&#xff0c;各有其独特的特性和优势。随着人工智能技术的快速发展&#xff0c;越来越多的开发者需要熟练掌握这两种工具&#xff0c;以便在实际项目中选择适合的框架进行高效开发。 目录 入门友好介绍 Te…

【C++】2029:【例4.15】水仙花数

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目描述&#x1f4af;我的做法思路分析优势不足之处 &#x1f4af;老师的做法思路分析优势不足 &#x1f4af;对比和优化实现方式对比优化思路和操作1. 直接分解数字的各位…

结合长短期记忆网络(LSTM)和无迹卡尔曼滤波器(UKF)的技术在机器人导航和状态估计中的应用前景

结合长短期记忆网络(LSTM)和无迹卡尔曼滤波器(UKF)的技术在机器人导航和状态估计中具有广泛的应用前景。如有滤波、导航方面的代码定制需求,可通过文末卡片联系作者获得帮助 文章目录 结合LSTM和UKF的背景结合LSTM和UKF的优势应用实例研究现状MATLAB代码示例结论结合LSTM和…

Android14 CTS-R6和GTS-12-R2不能同时测试的解决方法

背景 Android14 CTS r6和GTS 12-r1之后&#xff0c;tf-console默认会带起OLC Server&#xff0c;看起来olc server可能是想适配ATS(android-test-station)&#xff0c;一种网页版可视化、可配置的跑XTS的方式。这种网页版ATS对测试人员是比较友好的&#xff0c;网页上简单配置下…

告别Kibana:Elasticsearch 桌面客户端的新变革

告别Kibana&#xff1a;Elasticsearch 桌面客户端的新变革 在大数据处理与分析领域&#xff0c;Elasticsearch 及其相关技术的应用日益广泛。长期以来&#xff0c;Kibana 在数据可视化与查询管理方面占据重要地位&#xff0c;但随着技术的不断发展&#xff0c;用户对于更高效、…

HTML5实现喜庆的新年快乐网页源码

HTML5实现喜庆的新年快乐网页源码 前言一、设计来源1.1 主界面1.2 关于新年界面1.3 新年庆祝活动界面1.4 新年活动组织界面1.5 新年祝福订阅界面1.6 联系我们界面 二、效果和源码2.1 动态效果2.2 源代码 源码下载结束语 HTML5实现喜庆的新年快乐网页源码&#xff0c;春节新年网…

【广州计算机学会、广州互联网协会联合主办 | ACM独立出版 | 高录用】第四届大数据、信息与计算机网络国际学术会议(BDICN 2025)

第四届大数据、信息与计算机网络国际学术会议&#xff08;BDICN 2025&#xff09;定于2025年01月10-12日在中国广州举行。会议旨在为从事“大数据”、“计算机网络”与“信息”研究的专家学者、工程技术人员、技术研发人员提供一个共享科研成果和前沿技术&#xff0c;了解学术发…

C语言函数栈帧的创建和销毁

文章目录 一、寄存器二、函数栈帧的创建和销毁1.什么是函数栈帧&#xff1f;2.案例代码-讲解3.总结函数栈帧 一、寄存器 寄存器(Register)是中央处理机、主存储器和其他数字设备中某些特定用途的存储单元。寄存器是集成电路中非常重要的一种存储单元&#xff1b;其可用来暂存指…

我的博客年度之旅:感恩、成长与展望

目录 感恩有你 技能满点 新年新征程 嘿&#xff0c;各位技术大佬、数码潮咖还有屏幕前超爱学习的小伙伴们&#xff01;当新年的钟声即将敲响&#xff0c;我们站在时光的交汇点上&#xff0c;回首过往&#xff0c;满心感慨&#xff1b;展望未来&#xff0c;豪情满怀。过去的这…

【数据库初阶】MySQL数据类型

&#x1f389;博主首页&#xff1a; 有趣的中国人 &#x1f389;专栏首页&#xff1a; 数据库初阶 &#x1f389;其它专栏&#xff1a; C初阶 | C进阶 | 初阶数据结构 亲爱的小伙伴们&#xff0c;大家好&#xff01;在这篇文章中&#xff0c;我们将深入浅出地为大家讲解 MySQL…

webrtc 源码阅读 make_ref_counted模板函数用法

目录 1. 模板参数解析 1.1 typename T 1.2 typename... Args 1.3 typename std::enable_if::value, T>::type* nullptr 2. scoped_refptr 3. new RefCountedObject(std::forward(args)...); 4. 综合说明 5.在webrtc中的用法 5.1 peerConnectionFactory对象的构建过…

python参数传递不可变对象含可变子对象

当传递不可变对象时。不可变对象里面包含的子对象是可变的。则方法内修改了这个可变对象&#xff0c;源对象也发生了变化。 a (10, 20, [5, 6]) print("a", id(a))def test01(m):print("m", id(m))m[2][0] 888print("修改m后m的值为{}".forma…

qt5.15.2+visual studio2022 免安装版环境配置

1.环境准备 visual studio2022qt5.15.2&#xff08;免安装版本&#xff09; 2.环境配置 2.1 打开首选项 2.2 添加Qt版本 2.3 构建套件手动添加Qt 5.15.2&#xff08;msvc2019_64&#xff09;并配置如下 3.新建项目 问题1&#xff1a;qt creator 没有欢迎界面 解决办法&#…

KOI技术-事件驱动编程(Sping后端)

1 “你日渐平庸&#xff0c;甘于平庸&#xff0c;将继续平庸。”——《以自己喜欢的方式过一生》 2. “总是有人要赢的&#xff0c;那为什么不能是我呢?”——科比布莱恩特 3. “你那么憎恨那些人&#xff0c;和他们斗了那么久&#xff0c;最终却要变得和他们一样&#xff0c;…