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

java 函数接口Consumer简介与示例【函数式编程】【Stream】

Java 8 中的 消费者接口Consumer 是一个函数接口,它可以接受一个泛型 类型参数,它属于java.util.function包。我们来看看Java函数接口库中的定义:

@FunctionalInterface
public interface Consumer<T> {/*** Performs this operation on the given argument.** @param t the input argument*/void accept(T t); //抽象方法/***下面是一个默认方法***/default Consumer<T> andThen(Consumer<? super T> after) {Objects.requireNonNull(after);return (T t) -> { accept(t); after.accept(t); };}
}

accept(T) 方法:是 Consumer 函数式接口的惟一抽象方法,传入单个输入参数,无返回值,可以用于 Lambda 表达式和方法引用。
andThen(Consumer) 方法:是默认方法。上面是这个默认方法的源代码。它可以传入一个 Consumer ,返回组合了两个 Consumer 后的 Consumer ,传入的 Consumer 不能为 null,否则会得到 NullPointerException 。

你可以使用 Consumer 来执行某个动作,比如打印操作、集合中的删除操作等等,该动作接受一个参数并且不返回任何值。

我们先来看两个例程。
第一个例程演示了Consumer 函数式接口两个方法的调用:

import java.util.function.Consumer;
public class ConsumerTest {public static void test() {Consumer<String> first = x -> System.out.println("1."+x.toLowerCase());Consumer<String> second = y -> System.out.println("2." + y);System.out.println("开始");Consumer<String> consume = first.andThen(second);//调用了accept 时,会先执行 first 的代码,再执行 second 的代码consume.accept("World");}public static void main(String[] args) {test();}
}

consume调用accept 方法时,会先执行 first 里的代码,再执行 second 里的代码
测试结果:
在这里插入图片描述

第二个例程:演示集合中的forEach()方法使用Consumer 函数式接口,这是Consumer 函数式接口最常见的用法。

package function;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
public class ConsumerTest {//Consumer接口的匿名实现类版本public static void test1() {List<String> list = Arrays.asList("我","爱","北京天安门");list.forEach( new Consumer<String>() {@Overridepublic void accept(String string) {System.out.println(string);}}  );}public static void main(String[] args) {test1();}
}

这段程序很简单,首先初始化一个String类型的集合List,然后向控制台输出集合中每个元素。其中我们注意到forEach方法,它就是Java8中新增加的默认方法。

集合框架中的集合类都实现了迭代接口,forEach方法是Iterable接口的默认方法,被关键字default修饰。这样任何实现该接口的集合都继承forEach方法。Iterable接口的源码如下:

public interface Iterable<T> {..省略.default void forEach(Consumer<? super T> action) {Objects.requireNonNull(action);for (T t : this) {action.accept(t);}}
}

如上所示,forEach的实现,首先接收了一个Consumer类型的参数action,进行非空判断,然后遍历当前所有元素,并由action的accept方法进行处理。
forEach方法的输入参数就是一个Consumer类型的参数action。本例中方法test1()是Java7以前版本的老式写法,传入的是一个Consumer接口的匿名实现类:

new Consumer<String>() {@Overridepublic void accept(String string) {System.out.println(string);}
}

在Java8以后版本,第二种方式,函数式接口实例可以使用Lambda表达式,这个Consumer接口的匿名实现类可简写成:
string->System.out.println(string) 此Lambda表达式接收一个参数,没有返回值。
因此,方法test1()就可以改写为如下的Lambda表达式版本:

	//Lambda表达式版本public static void test1() {List<String> list = Arrays.asList("我","爱","北京天安门");list.forEach( string->System.out.println(string) );}

Lambda表达式:string->System.out.println(string)
函数式接口实例第三种方式:方法引用。方法引用的语法是 对象::方法名。还可改写为方法引用 : System.out::println
这二种写法是等效。
所以,我们还可以改写为如下的方法引用的版本:

	//方法引用的版本public static void test1() {List<String> list = Arrays.asList("我","爱","北京天安门");list.forEach( System.out::println );}

改写后版本的效果与前面的Consumer接口的匿名实现类版本完全等价。

再来看一个例子test3(),这个例子中用到了二个Consumer函数,其中consumer是Consumer接口的实现类,还有一个直接使用了Lambda的方法调用:System.out::println

	public static void test3() {List<String> list = new ArrayList<>();Consumer <String> consumer  = x -> {if (x.startsWith("w")){list.add(x);}};Stream.of( "boy","word","cat","way" ).forEach(consumer);list.forEach(System.out::println);}

我们再来看一个复杂一点的例子,例程中用到了集合数组列表,还有一个自定义的类Person。test4()的源代码如下:

	public static void test4() {List<Person> list = new ArrayList<>();list.add(new Person("张振华", 30));list.add(new Person("王五", 28));list.add(new Person("李四", 26));list.add(new Person("李世民", 26));Consumer <Person> consumer  = p -> {if (p.getName().startsWith("张")){list.add(p);}};consumer = consumer.andThen(x -> list.removeIf(y -> y.getName().startsWith("李")));list.forEach(System.out::println);System.out.println("***************************");Stream.of(new Person("王明",32),new Person("张三",18)).forEach(consumer);list.forEach(System.out::println);}

下面是完整的测试例程,有兴趣的读者可以进行编译调试:

package function;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Stream;
public class ConsumerTest {public static void test1() {List<String> list = Arrays.asList("我","爱","北京天安门");//list.forEach(System.out::println);list.forEach(string->System.out.println(string));/*list.forEach( new Consumer<String>() {@Overridepublic void accept(String string) {System.out.println(string);}}  );*/}public static void test3() {List<String> list = new ArrayList<>();Consumer <String> consumer  = x -> {if (x.startsWith("w")){list.add(x);}};Stream.of( "boy","word","cat","way" ).forEach(consumer);list.forEach(System.out::println);}public static void test() {// 创建一个Consumer实例,打印输入的字符串Consumer<String> printer = System.out::println;// 使用accept方法来消费(使用)一个值printer.accept("没有共产党就没有新中国!");// 另一个使用Consumer的例子,这次是更新对象的某个字段的值Consumer<Person> increaseAge = person -> person.setAge(person.getAge() + 1);// 创建一个Person对象Person person = new Person("张振华", 30);// 使用Consumer来增加年龄increaseAge.accept(person);// 打印出增加年龄后的结果System.out.println(person.getName() + ": " + person.getAge());}public static void test4() {List<Person> list = new ArrayList<>();list.add(new Person("张振华", 30));list.add(new Person("王五", 28));list.add(new Person("李四", 26));list.add(new Person("李世民", 26));Consumer <Person> consumer  = p -> {if (p.getName().startsWith("张")){list.add(p);}};consumer = consumer.andThen(x -> list.removeIf(y -> y.getName().startsWith("李")));list.forEach(System.out::println);System.out.println("***************************");Stream.of(new Person("王明",32),new Person("张三",18)).forEach(consumer);list.forEach(System.out::println);}public static void main(String[] args) {test1();test3();test();test4();}
}class Person {private String name;private int age = 32;public Person(String name) { // 构造器this.name = name;}// 构造器public Person(String name, int age) {this.name = name;this.age = age;}// getter和setter方法public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "姓名:"+name + "  年龄:"+age;}
}

程序测试结果:
在这里插入图片描述

相关文章:

java 函数接口Consumer简介与示例【函数式编程】【Stream】

Java 8 中的 消费者接口Consumer 是一个函数接口&#xff0c;它可以接受一个泛型 类型参数&#xff0c;它属于java.util.function包。我们来看看Java函数接口库中的定义&#xff1a; FunctionalInterface public interface Consumer<T> {/*** Performs this operation o…...

黑神话:悟空-配置推荐

显卡推荐&#xff08;按类别整理&#xff09; 1. GTX 10系列、GTX 16系列&#xff1a; 如果希望体验光线追踪&#xff0c;建议根据预算升级到RTX 40系列显卡。对于1080p分辨率&#xff0c;至少需要RTX 4060才能流畅运行。 2. RTX 20系列&#xff1a; RTX 2060、RTX 2070&#…...

Android14 蓝牙设备类型修改

Android14 蓝牙设备类型设置修改设置 文章目录 Android14 蓝牙设备类型设置修改设置一、前言二、修改蓝牙设备类型1、蓝牙设备类型和对应的属性2、Debug设备设置和获取蓝牙设备类型3、系统源码中设置蓝牙设备类型4、Java代码中设置蓝牙prop属性可行吗&#xff1f; 三、其他1、A…...

vue3 语法糖<script setup>

在 Vue 3 中&#xff0c;<script setup>是一种新的语法糖&#xff0c;它极大地简化了组件的编写方式。 <script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。当同时使用 SFC 与组合式 API 时该语法是默认推荐。 基本概念 简洁的语法&#xf…...

微服务设计原则——高性能:异步与并发

文章目录 1.异步1.1 调用异步1.2 流程异步1.3 数据流异步1.4 小结 2.并发2.1 请求并发2.2 冗余请求2.3 小结 参考文献 1.异步 对于处理耗时长的任务&#xff0c;如果采用同步等待的方式&#xff0c;会严重降低系统的吞吐量&#xff0c;可以采用异步化进行解决。 异步&#xf…...

机器学习——决策树,朴素贝叶斯

一.决策树 决策树中的基尼系数&#xff08;Gini Index&#xff09;是用于衡量数据集中不纯度&#xff08;或混杂度&#xff09;的指标。基尼系数的取值范围在0到0.5之间&#xff0c;其中0表示数据完全纯&#xff08;同一类别&#xff09;&#xff0c;0.5表示数据完全混杂。 基…...

C语言基础(十)

编译预处理命令&#xff1a; 预编译命令在C语言中用于在编译前进行一些特定的处理和控制&#xff0c;帮助程序员更灵活地管理源代码和控制编译过程。 C语言常用的预编译命令&#xff1a; #include&#xff1a;用于包含头文件&#xff0c;将另一个文件的内容插入到当前文件中…...

人像比对-人证比对-人脸身份证比对-人脸身份证实名认证-人脸三要素对比-实人认证

人脸身份证实名认证是一种基于生物识别技术的身份验证方式&#xff0c;主要依托证件OCR识别技术、活体检测、人脸比对等技术手段&#xff0c;对用户身份信息真实性进行核验&#xff0c;确保用户为真人且为本人。以下是关于人脸身份证实名认证的详细解析&#xff1a; 一、认证流…...

Android 上下滑隐藏显示状态栏

一、DisplayPolicy类中监听滑动事件&#xff0c;然后发送广播事件 Android12类路径&#xff1a; frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.javamSystemGestures new SystemGesturesPointerEventListener(mUiContext, mHandler,new SystemGest…...

USBCAN-II/II+使用方法以及qt操作介绍

一.USBCAN-II/II介绍 USBCAN-II/II 是一款常用的 USB-CAN 转换器&#xff0c;广泛应用于汽车电子、工业自动化等领域。以下是使用该设备的一般步骤和方法&#xff1a; 1. 硬件连接 连接设备&#xff1a;将 USBCAN-II/II 的 USB 接口连接到计算机的 USB 端口。 连接 CAN 网络…...

笔记-系统规划与管理师-案例题-2022年-IT服务部署实施

【说明】 某大型企业去年信息化投入大&#xff0c;完成了重点核心业务系统的建设。由于应急相应预案制定得不充分并且未开展演练&#xff0c;出现了系统性故障时&#xff0c;部分关键的应用系统不可用且在12小时内未能完成恢复业务&#xff0c;给企业带来了较大损失。 为加强该…...

Kubernetes 清理资源常用的 Kubernetes 清理命

清理特定状态的 Pod&#xff1a; 清理 Evicted 状态的 Pod&#xff1a; kubectl get pods --all-namespaces -o wide | grep Evicted | awk {print $1,$2} | xargs -L1 kubectl delete pod -n清理 Error 状态的 Pod&#xff1a; kubectl get pods --all-namespaces -o wide | g…...

【数据结构初阶】二叉树--基本概念

hello&#xff01; 目录 一、树 1.1 树的概念和结构 1.2 树的相关术语 1.3 树的表示 1.4 树形结构实际应用场景 二、二叉树 2.1 概念和结构 2.2 特殊的二叉树 2.2.1 满二叉树 2.2.2 完全二叉树 2.3 二叉树的存储结构 2.3.1 顺序结构 2.3.2 链式结构 …...

Pytorch添加自定义算子之(12)-开闭原则设计tensorrt和onnxruntime推理语义分割模型

一、开闭原则 开闭原则是SOLID原则中的一个,指的是尽量使用开放扩展,关闭修改的设计原则。 在C++中如何使用开闭原则导出动态库,可以按照以下步骤进行: 定义抽象基类:定义动态库中的抽象基类,该基类应该封装可扩展的接口。 实现派生类:实现基类的派生类,这些派生类将封…...

第二百零九节 Java格式 - Java数字格式类

Java格式 - Java数字格式类 以下两个类可用于格式化和解析数字: java.text.NumberFormatjava.text.DecimalFormat NumberFormat 类可以格式化一个数字特定地区的预定义格式。 DecimalFormat 类可以格式化数字以特定区域设置的自定义格式。 NumberFormat类的 getXXXInstance…...

LSI-9361阵列卡笔记

背景 要将raid0更改为JBOD直通模式 注意的点是要先将raid模式调整为JBOD之后重启机器&#xff0c;即可 备注&#xff1a;转换过程中硬盘中的数据未丢失。 步骤贴图 refer https://zhiliao.h3c.com/questions/dispcont/123250 https://blog.csdn.net/GreapFruit_J/article/…...

ArcGIS热点分析 (Getis-Ord Gi*)——基于地级市尺度的七普人口普查数据的热点与冷点分析

先了解什么是热点分析 ? 热点分析 (Getis-Ord Gi*) 是一种用于空间数据分析的技术&#xff0c;主要用于识别地理空间数据中值的聚集模式&#xff0c;可以帮助我们理解哪些区域存在高值或低值的聚集&#xff0c;这些聚集通常被称为“热点”或“冷点”&#xff0c;Gi* 统计量为…...

ASIACRYPT 2021

分类文章编号获奖论文1-3后量子密码4-9多方计算10-15物理攻击,泄露和对策16-21理论22-27公钥密码和鉴权密钥交换28-33高级加密和签名34-39对称密钥构建40-46量子安全47-53获奖论文54对称密码分析55-66增强型公钥加密和时间锁难题67-72同态加密和加密搜索73-77NIZK和SNARK78-80…...

C#学习之路day1

目录 一、概念&#xff1a;.net和c# 二、.net发展方向 三、.Net两种交互模式 四、创建项目 五、vs的组成部分 六、我的第一个C#程序 七、多个项目时启动项目的设置 八、注释 九、快捷键 一、概念&#xff1a;.net和c# 1、.net/dotnet :一般指.Net Framework框架&#…...

【安当产品应用案例100集】010-基于国密UKEY的信封加密应用案例

安当有个客户开发了一套C/S架构的软件&#xff0c;Server在云端&#xff0c;Client由不同的用户使用。最初软件设计开发的时候&#xff0c;没有考虑数据安全形势日渐严峻的问题&#xff0c;Server端和Client端直接就建立一个socket连接来进行通信&#xff0c;Server端发出去的数…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

linux 错误码总结

1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”

2025年#高考 将在近日拉开帷幕&#xff0c;#AI 监考一度冲上热搜。当AI深度融入高考&#xff0c;#时间同步 不再是辅助功能&#xff0c;而是决定AI监考系统成败的“生命线”。 AI亮相2025高考&#xff0c;40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕&#xff0c;江西、…...

day36-多路IO复用

一、基本概念 &#xff08;服务器多客户端模型&#xff09; 定义&#xff1a;单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用&#xff1a;应用程序通常需要处理来自多条事件流中的事件&#xff0c;比如我现在用的电脑&#xff0c;需要同时处理键盘鼠标…...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...

永磁同步电机无速度算法--基于卡尔曼滤波器的滑模观测器

一、原理介绍 传统滑模观测器采用如下结构&#xff1a; 传统SMO中LPF会带来相位延迟和幅值衰减&#xff0c;并且需要额外的相位补偿。 采用扩展卡尔曼滤波器代替常用低通滤波器(LPF)&#xff0c;可以去除高次谐波&#xff0c;并且不用相位补偿就可以获得一个误差较小的转子位…...

stm32wle5 lpuart DMA数据不接收

配置波特率9600时&#xff0c;需要使用外部低速晶振...