JDK8新特性--函数式接口--(Consumer的概念理解,模拟练习,企业实战)全流程彻底搞懂

news2024/11/25 5:03:24

背景,起因是因为在项目开发过程中,发现了一处代码的写法觉得很新奇看不懂,了解后发现是用到了函数式接口的知识。特此学习记录,整体过程梳理在本文。如果你不满足就会写个CURD,业务代码只会new来new去,代码维护性差,本文可以给你提供思路,告诉你写出一个巨屌的代码,同样的逻辑,不同的写法,其他程序员一眼看的哇塞和懵逼。

1 本人对【函数式接口】的理解

  • 为什么以前没听说过这个东西?

答:JDK8新特性,Java提出了函数式接口。

  • 为什么要使用函数式接口?

使用函数式接口,提高了代码的灵活性,后面的案例会带你体验有多吊,吊打你以前的写法

  • 什么是函数式接口?

接下来会从两个维度解释。

维度一:资料定义
在这里插入图片描述

希望第一步你能够看懂这个解释,能看懂 【匿名内部类】和【lambda表达式】写法
若果这一步吃力的话,可以参考这篇文章,写的很基础和全面,通俗易懂
点击查看-> 匿名内部类、Lambda、方法引用 的总结


维度二:JDK提供的函数式接口

对于新手的我们,使用函数式接口,基本上就是使用JDK提供的大量函数式接口。不同场景下使用不同的函数式接口,现在还没能力去自定义一个函数式接口,让项目代码有优雅。

在搜索资料的过程中,了解到了一个新名词:Java语法糖
(为了不影响本文梳理逻辑,关于语法糖的介绍我放到了章节,右侧目录可以查看)

这里作者想要强调的是,使用JDK提供的函数式接口,让我们代码更优雅了,某种程度上符合
Java语法糖的思想。理解这一点,也就能更透彻的理解函数式接口这个设计的优点。

好了,回到正题

  • JDK提供了哪些函数式接口呢?
    在这里插入图片描述
    在这里插入图片描述
    本文介绍的是java.util.function包下的接口,其中核心的有
  • Supplier接口
  • Consumer接口
  • Predicate接口
  • Function接口
  • 等等

下面会介绍 Consumer接口使用案例

2 函数式接口–>Consumer接口案例

现在有一个需求:创建一个list列表,存储数据,直接打印列表的内容

@Test
public void demo(){
	List<String> list = Arrays.asList("John","Andy");
	printList(list);
}

public void printList(List<String> list){
	for(String s : list){
		System.out.println(s);
	}
}

现在我们的代码很优雅,客户需要打印功能,只需要调用printList方法就行,完全不需要操心如何实现的

现在客户需求变了:创建一个list列表,存储数据,将大写转化为小写后再打印列表的内容

@Test
public void demo(){
	List<String> list = Arrays.asList("John","Andy");
	printList(list);
}

public void printList(List<String> list){
	for(String s : list){
		//变动的地方
		System.out.println(s.toLowerCase);
	}
}

按照客户需求,只需要修改一次printList方法的内容就行了。完美解决

现在需求又又变了:创建一个list列表,存储数据,将小写转化为大写后再打印列表的内容

@Test
public void demo(){
	List<String> list = Arrays.asList("John","Andy");
	printList(list);
}

public void printList(List<String> list){
	for(String s : list){
		//变动的地方
		System.out.println(s.toUpperCase);
	}
}

再次按照客户需求,第二次修改printList方法的内容。完美解决

现在需求又又又又又变了…,是不是每次变动,都需要修改printList方法内容,这也太麻烦了。我打算把控制权给客户,需要什么自己去修改,不要动我 printList()方法的代码了。

如何实现呢,借用函数式接口Consumer

@Test
public void demo(){
	List<String> list = Arrays.asList("John","Andy");
	printList(list, new Consumer<String>() {
		@Override
		public void accpet(String s){
			System.out.println(s);
			//System.out.println(s.toLowerCase);
			//System.out.println(s.toUpperCase);
		}
	}
}

public void printList(List<String> list,Consumer<String> consumer){
	for(String s : list){
		consumer.accept(s);
	}
}

这里使用了匿名内部类的写法,实际上不这样写,而是使用lambda表达式,优化后的代码

@Test
public void demo(){
	List<String> list = Arrays.asList("John","Andy");
	printList(list, s-> System.out.println(s));
	}
}

public void printList(List<String> list,Consumer<String> consumer){
	for(String s : list){
		consumer.accept(s);
	}
}

分析一下,当程序运行后,开始调用printList方法,进入printList方法后,执行for循环,每次遍历都要执行accept方法,accept方法被重写了,就执行重写的内容。

当然了,看到这里你肯定会心有疑惑:我就是想要遍历+打印而已,怎么弄得这么复杂,还不如直接全写在demo()里面,使用最原始的方式。

这么想就错了,企业的项目是很复杂的,不是本案例演示的这些功能。

3 项目使用的案例

我现在得到一个json格式的字符串,需要将其解析后存到list中,得到list的长度,如果长度大于2,打印:我是2,否则打印:我是其他

3.1 普通写法

文件A
public class JsonUtils {
    public int parseJsonString(String jsonString) {
        JSONArray jsonArray = JSON.parseArray(jsonString);
        List<Person> personList = jsonArray.toJavaList(Person.class);
        int length = personList.size();
        return length;
    }
}
文件B
public class Example {
    public static void main(String[] args) {
        String jsonString = "[{\"name\":\"Alice\", \"age\":25}, {\"name\":\"Bob\", \"age\":30}]";
		
        int length = JsonUtils.parseJsonString(jsonString);
		
		printResult(length);
    }
    
	private static void printResult(int length) {
        if (length > 2) {
            System.out.println("我是2");
        } else {
            System.out.println("我是0");
        }
    }
}

这种普通写法是我们大家最习惯的写法,阅读起来完全没有问题。
注意分析主函数:我们一共传递了两次参数
在这里插入图片描述

那么接下来我们尝试修改为函数式接口的写法

3.2 lambda+函数式接口写法

看不懂代码,先看本章节后面结论

文件A
public class JsonUtils {
    public static void parseJsonString(String jsonString, Consumer<Integer> consumer) {
        JSONArray jsonArray = JSON.parseArray(jsonString);
        List<Person> personList = jsonArray.toJavaList(Person.class);
        int length = personList.size();
        consumer.accept(length);
    }
}
文件B

public class Example {
    public static void main(String[] args) {
        String jsonString = "[{\"name\":\"Alice\", \"age\":25}, {\"name\":\"Bob\", \"age\":30}]";

        Consumer<Integer> consumer = length -> {
            if (length > 2) {
                System.out.println("我是2");
            } else {
                System.out.println("我是其他");
            }
        };

		//将该Lambda表达式传递给JsonUtils类的parseJsonString方法,以执行解析JSON字符串、获取列表长度并打印结果信息的操作。
        JsonUtils.parseJsonString(jsonString, consumer);
    }
}

看看能否理解此代码?
在这里插入图片描述
可以看到此部分的代码使用了函数式接口+lambda表达式,希望大家先知道如何写这种风格的代码,作者知道大家一定一定会非常疑惑,改造后的代码怎么感觉更乱了,一点没看出来哪里优雅,总不能说使用了函数式接口就优雅。
注意看,粗看感觉很乱,仔细分析主函数内容:
在这里插入图片描述

可以发现,我们这次只传递了一次参数。只不过lambda表达式那一坨看着很恶心,不美观。要是能抽离出去,成为一个单独的方法就好了

3.3 方法引用+函数式接口写法

A 文件

public class JsonUtils {
    public static void parseJsonString(String jsonString, Consumer<Integer> consumer) {
        JSONArray jsonArray = JSON.parseArray(jsonString);
        List<Person> personList = jsonArray.toJavaList(Person.class);
        int length = personList.size();
        consumer.accept(length);
    }
}
B 文件

public class Example {
    public static void main(String[] args) {
        String jsonString = "[{\"name\":\"Alice\", \"age\":25}, {\"name\":\"Bob\", \"age\":30}]";

        Consumer<Integer> consumer = Example::printResult;

        JsonUtils.parseJsonString(jsonString, consumer);
    }

    private static void printResult(int length) {
        if (length > 2) {
            System.out.println("我是2");
        } else {
            System.out.println("我是其他");
        }
    }
}

这种写法简直太完美:传递一次参数,代码简洁。

4 总结

总结一下:

在这里插入图片描述
这里作者可以再具体说说有什么好处。

原客户需求:我现在得到一个json格式的字符串,需要将其解析后存到list中,得到list的长度,如果长度大于2,打印:我是2,否则打印:我是其他

现在客户需求变了,且需要你的同事负责开发:

  • 我现在得到一个json格式的字符串,需要将其解析后存到list中,得到list的长度,

  • 如果长度小于2,打印:我比2小;

  • 长度等于2,打印:我是2;

  • 长度大于2,打印:我比2大

如果你按照最初代码版本写的
你的同事:需求修改printResult()方法内容,然后在主函数进行测试:调用parseJsonString()方法获取返回值,将返回值传递给printResult()方法

如果你按照最初代码版本写的
你的同事:需求修改printResult()方法内容,然后在主函数进行测试:不需要改动代码

神奇吧,神奇吧,就是这么玩的。第一次写完后,以后的程序员不需要关心调用了什么方法,传递了什么参数,他需要做的仅仅就是修改业务代码printResult()。这代码质量太高了。拓展性,封装性,维护性都考虑到了。

5 我的企业代码实战案例

文件A.java

@Override
    public void afterPropertiesSet() throws Exception {
        
          SyslogDataSyncConsumer<String, String> consumer = new SyslogDataSyncConsumer<String, String>;
          
          Integer syncCount = consumer.consumerInfo(
                           	Collections.singletonList(KafkaTopicConst.Event_BMS_SYSLOG_ROLE),
                            consumer::handle);
      }

     public void handle(ConsumerRecords<String, String> records) {........(业务功能处理)    }      
      
文件B.java

public Integer consumerInfo(List<String> topics,
                                Consumer<ConsumerRecords<K, V>> recordsHandler)
  {
        // 拉取超时毫秒数,如果没有新的消息可供拉取,consumer会等待指定的毫秒数,到达超时时间后会直接返回一个空的结果集
        ConsumerRecords<K, V> records = null;
        
  		....
		//省略详细处理recods过程
		....
		
        //kafka消息处理器处理读取到的消息
        recordsHandler.accept(records);
  }

能看懂此代码吗?
内部的原理就是图示的流程
这里解释一下,

5 语法糖

在这里插入图片描述
通俗点解释,我们在写代码的时候,需要尽量争取让我们的代码更优雅,更容易理解。
比如正常遍历数组arrayTest

for(int i = 0; i < arrayTest.seize(); i++){
	Sysytem.out.println(arrayTest[i]);
}

JDK1.5版本后,支持使用增强for循环写法

for (String s : arrayTest) {
    Sysytem.out.println(s);     
}

可以看到这种效果是不是更优雅,更不容易出错(不用担心循环次数,数组下标是否正确)

还有哪些地方用到了语法糖,参考本文链接---->[点击查看]

10 JDK8的新特性有哪些

点击查看–> JDK8的新特性参考文章

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring 中三种 BeanName 生成器!

无论我们是通过 XML 文件&#xff0c;还是 Java 代码&#xff0c;亦或是包扫描的方式去注册 Bean&#xff0c;都可以不设置 BeanName&#xff0c;而 Spring 均会为之提供默认的 beanName&#xff0c;今天我们就来看看 Spring 中三种处理不同情况的 beanName 生成器。 1. BeanN…

零基础Linux_4(权限和初识操作系统)具体用户分类+rwx+umask+粘滞位

目录 1. 操作系统初识 1.1 操作系统的基本概念 1.2 操作系统的意义 1.3 指令操作的意义 2. shell命令及运行原理 2.1 shell的概念 2.2 shell 的意义 3. Linux权限 3.1 Linux 具体用户的分类 3.2 用户管理 adduser 新用户名(添加普通用户) 用户登陆 - SSH 用户名 u…

视频号挂公众号链接没完全堵死,还能加,最新方法教程,玩私域流量的福音来了

视频号挂公众号链接 视频号挂公众号链接&#xff0c;不限号&#xff0c;不限次数&#xff0c;不需要绑定公众号&#xff0c;不需要10000阅读量 视频号评论区能挂链接&#xff0c;对视频号做公转私的人来说&#xff0c;可以说是大惊喜&#xff0c;对公司来讲放上自己的推广链接…

前缀和实例1 (【模板】前缀和 )

题目&#xff1a; 算法原理&#xff1a; 前缀和算法能快速求出某一个区间内所有元素的和 1 预处理出来一个前缀和数组dp dp[i] dp[i-1]v[i] (v数组由输入的数字组成&#xff09;&#xff0c;即区间[1,i]的所有元素的和区间[1,i-1]所有元素的和v数组中i下标的元素 2 使用前缀…

获取1688店铺详情 API接口(获取卖家昵称、店铺类型、公司信息、店铺标题、店铺主页)

seller_info-获得店铺详情 1688.seller_info进入测试 公共参数 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥api_nameString是API接口名称&#xff08;包括在请求地址中&#xff09;[item_search,item_get,it…

计算机竞赛 大数据商城人流数据分析与可视化 - python 大数据分析

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于大数据的基站数据分析与可视化 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度…

探索移动应用的自动化测试:如何做出明智的工具选择

引言 随着移动应用的日益普及&#xff0c;其在日常生活和工作中的作用也越来越大。为了确保应用的稳定性和用户体验&#xff0c;自动化测试已经成为了开发流程中不可或缺的一部分。本文将深入探讨如何为移动应用选择合适的自动化测试工具&#xff0c;以及这些工具背后的技术原…

【广州华锐互动】云智慧工厂数字孪生:打造高效、灵活的智能制造新模式

随着工业4.0的到来&#xff0c;数字孪生技术逐渐成为实现工业生产智能化升级的关键。云智慧工厂数字孪生利用先进的数字化技术&#xff0c;创建物理实体的虚拟模型&#xff0c;实现对生产过程的实时监控、优化与管理。 云智慧工厂数字孪生是指通过数字孪生技术&#xff0c;构建…

考研英语笔记:程序员是否勤奋就看他的英语好不好

一位大佬朋友圈写道&#xff1a;看程序员是否勤奋就看他的英语好不好&#xff0c;智商高不高就看他算法好不好。 这句话我当时看到了很触动&#xff0c;默默的记在了心底。 对我来说&#xff0c;算法就免了&#xff0c;但学英语我一直在坚持。我不敢说我是优秀的程序员&#xf…

如何在三星手机上截屏?每一款三星手机的每一种方法,包括S23

无论你是将截图作为保存图片、消息或信息的快速方式&#xff0c;还是作为演示像这篇文章这样有用的操作方法的方式&#xff0c;能够截图都会非常有用。 但并不是所有的手机都以相同的方式进行屏幕截图。事实上&#xff0c;并不是所有的三星手机都能做到这一点。例如&#xff0…

MySql安装包配置

电脑重配过多次&#xff0c;此为mysql安装记录贴&#xff0c;方便查阅 从官网下载的安装包进行本地配置 下载地址 解压下载下来的zip压缩包 解压出来的文件中新增配置my.ini文件 [mysqld] # 设置3306端口 port3306 # 设置mysql的安装目录 basedirD:\\software\\package\\M…

神经网络 05(损失函数)

一、损失函数 在深度学习中, 损失函数是用来衡量模型参数的质量的函数, 衡量的方式是比较网络输出和真实输出的差异&#xff0c;损失函数在不同的文献中名称是不一样的&#xff0c;主要有以下几种命名方式&#xff1a; 损失函数 &#xff08;loss function&#xff09; 代价函…

科研小工具|胰岛素敏感性计算公式

简介 胰岛素敏感就是描述胰岛素抵抗的程度。 计算方式 HOMA-IR是用于评价个体胰岛素抵抗水平的指标。计算方法如下&#xff1a; 胰岛素抵抗指数&#xff08;HOMA-IR&#xff09;空腹血糖&#xff08;FPG&#xff0c;mmol/L&#xff09;空腹胰岛素&#xff08;FINS&#xff0…

上海某游戏小厂面试,也扛不住了...

今天分享一位同学面试上海某游戏公司的面经&#xff0c;同学的技术栈是Java后端&#xff0c;虽然不是大厂&#xff0c;但是一面面试也被问了 25 多个问题&#xff0c;时长也接近 1 小时了 面试过程中&#xff0c;也问到了 Linux socket 编程&#xff0c;游戏公司都会对网络协议…

封神台----为了女神小芳

目录 目录 前言 文章框架 1&#xff0c;题目 2&#xff0c;实验前的准备 3&#xff0c;进入传送门 4,使用Sqlmap对网站进行监测 4.1.检测目标地址是否存在注入点 4.2、检测数据库中的库名 4.3、选择需要爆的库开始爆表名 4.3.1,后面内容的一些注意点: 4.3.2,开始进…

esxi下实现ikuai相同的两个网卡,单独路由配置

1.首先安装配置双网卡。 因为esxi主机只接入了一根外网的网线&#xff0c;那么我们这两个网卡都是一样的网卡&#xff0c;具体的到系统里面进行设置。 2.开机安装系统 进入配置界面&#xff0c;此处就不用多说了&#xff0c;可以看我之前的文档&#xff0c;或者网上其他人的安…

中文版Chatbase轻松帮你实现智能回复

在数字时代&#xff0c;信息量可以说是爆炸性增长&#xff0c;很多企业网站都面临着一个共同的问题&#xff1a;如何在繁忙时还能为访客提供及时而有用的回复&#xff1f;那我可以坚定地说AI问答机器人可以做到。很多人都知道使用Chatbase可以创建聊天机器人来即时回答访客的问…

vue2配置环境变量并且nginx运行成功

需求&#xff1a;我在vue项目配置了生产环境和开发环境&#xff0c;之后通过proxy代理的方式把地址转发到真实的服务器地址上用于请求接口&#xff0c;之后把项目打包后上传到nginx上&#xff0c;之后接口报错404&#xff0c;但是本地运行是可以访问的&#xff0c;找了很久终于…

滑动窗口详解

滑动窗口本质其实也是一种双指针算法&#xff0c;只是因为它维护的区间随着遍历的进行在不停变化&#xff0c;所以形象地称为“滑动窗口” 一、⻓度最⼩的⼦数组 题目要求找到满足条件的长度最小的子数组&#xff0c;我们先来想想暴力的做法&#xff0c;再来想想能不能优化&am…

LeetCode 1462. 课程表 IV:拓扑排序

【LetMeFly】1462.课程表 IV&#xff1a;拓扑排序 力扣题目链接&#xff1a;https://leetcode.cn/problems/course-schedule-iv/ 你总共需要上 numCourses 门课&#xff0c;课程编号依次为 0 到 numCourses-1 。你会得到一个数组 prerequisite &#xff0c;其中 prerequisite…