Java 函数式编程实例
一、函数式编程概念
函数式编程是一种编程的范式和编程的方法论(programming paradigm),它属于结构化编程的一种,主要的思想是把运算的过程尽量通过一组嵌套的函数来实现。
函数式编程的几个特点:
- 函数可以作为变量、参数、返回值和数据类型。
- 基于表达式来替代方法的调用
- 函数无状态,可以并发和独立使用
- 函数无副作用,不会修改外部的变量
- 函数结果确定性;同样的输入,必然会有同样的结果。
函数式编程的优点:
- 代码简洁,开发效率高
- 接近自然语言,易于理解
- 由于函数的特性,易于调试和使用
- 易于并发使用
- 脚本语言的特性,易于升级部署
二、@FunctionalInterface 函数式接口
@FunctionalInterface是 Java 8 新加入的一种接口,注解在接口层面,且注解的接口要有且仅有一个抽象方法。具体就是说,注解在Inteface上,且interface里只能有一个抽象方法,可以有多个default方法。
函数式接口的一大特性就是可以被lambda表达式和函数引用表达式代替
三、Lambda 表达式
Lambda 表达式是一种匿名函数(对 Java 而言这并不完全正确,但现在姑且这么认为),简单地说,它是没有声明的方法,也即没有访问修饰符、返回值声明和名字。
你可以将其想做一种速记,在你需要使用某个方法的地方写上它。当某个方法只使用一次,而且定义很简短,使用这种速记替代之尤其有效,这样,你就不必在类中费力写声明与方法了。
四、使用场景
4.1、Redis工具类
JAVA是面向对象的,通常方法的入参都是类(对象),或者变量,而函数式编程,就是把一个函数(方法)作为入参,那这个有啥好处呢??
简单举个例子,
当多个方法都有同样的操作时,我们通常想的是将其共同抽象成独立方法,但是整个流程是一样的,只是不同场景下,具体业务处理处理不同时,我们该怎么抽象呢?如果像下面那样操作,明显就是破坏了整个业务流程
public Object common1(){return "common1";}public Object common2(){return "common2";}public void method1(Object o){Object o1 =this.common1();//doSomeingSystem.out.println("========"+o1);this.common2();}public void method2(Object o){Object o1 =this.common1();//doSomeingSystem.out.println("-----------"+o1);this.common2();}
那想再不破坏整个流程的情况改怎么处理呢?可以利用函数式编程,把接口作为入参,当具体业务处理时再去实现其具体业务。
@FunctionalInterface
public interface Operation<T,R> {public T operate(R r);
}public void common(Operation<Object,Object> operation){//step1Object o1 =this.common1();operation.operate(o1);//step3this.common2();}public void method1Operation(Object o){this.common(o1 -> "========"+o1);}public void method2Operation(Object o){this.common(o1 -> "========"+o1);}
上面的介绍过于抽象,下面介绍一个很实用的场景。
对于一些池的操作,比如redisPool,或者线程池,都有一些通用的操作,首先,先从池中取出对象,然后实现具体业务,然后再把对象放入池中;
可以看出这里有操作流程上有重复的地方,如果我们把这写都写在具体业务中,过于耦合和繁琐,那我们就可以像上面的demo一样,将其公用部分抽象出来,这里已redisPool为例,如下
@FunctionalInterface
public interface Operation<T,R> {public T operate(R r);}
public class RedisTool2 {private static final String LOCK_SUCCESS = "OK";private static final Long RELEASE_SUCCESS = 1L;//NX|XX, NX -- Only set the key if it does not already exist;// XX -- Only set the key if it already exist.private static final String SET_IF_NOT_EXIST = "NX";//EX|PX, expire time units: EX = seconds; PX = millisecondsprivate static final String SET_WITH_EXPIRE_TIME = "PX";private static volatile JedisPool jedisPool = null;public static JedisPool getRedisPoolUtil() {if(null == jedisPool ){synchronized (RedisTool2.class){if(null == jedisPool){GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();poolConfig.setMaxTotal(100);poolConfig.setMaxIdle(10);poolConfig.setMaxWaitMillis(100*1000);poolConfig.setTestOnBorrow(true);jedisPool = new JedisPool(poolConfig,"192.168.10.151",6379);}}}return jedisPool;}public static <T> T doOperation(Operation<T,Jedis> operation){Jedis jedis = jedisPool.getResource();try {return operation.operate(jedis);}catch (Exception e){return null;}finally {jedisPool.returnResource(jedis);}}//使用匿名内部类实现public static boolean tryGetDistributedLock1(final String lockKey, final String requestId, final int expireTime) {return doOperation(new Operation<Boolean, Jedis>() {public Boolean operate(Jedis jedis) {String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);if (LOCK_SUCCESS.equals(result)) {return true;}return false;}});}//使用lambda表达式实现public static boolean tryGetDistributedLock2(final String lockKey, final String requestId, final int expireTime) {return doOperation(jedis ->{String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);if (LOCK_SUCCESS.equals(result)) {return true;}return false;});}//使用lambda表达式实现public static boolean tryGetDistributedLock2(final String lockKey, final String requestId, final int expireTime) {String result = doOperation(jedis ->jedis.set(lockKey, requestId, SET_IF_NOT_EXIST,SET_WITH_EXPIRE_TIME, expireTime));return LOCK_SUCCESS.equals(result);}public boolean releaseDistributedLock(String lockKey, String requestId) {String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";Object result = this.execute(jedis ->jedis.eval(script, Collections.singletonList(COMMON_LOCK_KEY+lockKey), Collections.singletonList(requestId)));return RELEASE_SUCCESS.equals(result);}//普通方法public static boolean tryGetDistributedLock(String lockKey, String requestId, int expireTime) {Jedis jedis = jedisPool.getResource();try {String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);if (LOCK_SUCCESS.equals(result)) {return true;}return false;}catch (Exception e){return false;}finally {jedisPool.returnResource(jedis);}}
}
4.2、分布式定时任务
@FunctionalInterface
public interface Operation {public void execJob();}
抽象基类:把获取锁和释放锁抽象到寄类实现,在具体业务job不用关心这些
@Component
public abstract class AbstractBasicTask {private static final Logger logger = LoggerFactory.getLogger(AbstractBasicTask.class);@AutowiredRedisService redisService;public void doOperation(String taskName,Operation operation){String requestId = DateUtils.getNowTimeMill();// 控制并发锁if (redisService.tryGetDistributedLock(taskName, requestId,600)) {long start = System.currentTimeMillis();try {// 开始执行定时任务operation.execJob();logger.info("{}:执行定时任务完成,耗时(毫秒):{}", taskName, (System.currentTimeMillis() - start));} catch (Exception e) {logger.error(taskName + ":执行定时任务异常", e);} finally {// 释放锁try {redisService.releaseDistributedLock(taskName,requestId);} catch (Exception e) {logger.error(taskName + ":释放锁异常", e);}}} else {logger.info("{}:获取锁失败", taskName);}}/*** 执行JOB业务逻辑*/public abstract void exec();
具体执行任务demoJob
@Component
@EnableScheduling
public class demoJob extends AbstractBasicTask{@Scheduled(cron = "1 * * * * ?")@Overridepublic void exec() {this.doOperation("demoJob", this::testA);}private void testA(){System.out.println("=========");}
}
总结:比较常用的,典型的应用场景,是当我们运算的过程可以抽象成好几个步骤时,把其中相同部分,抽象成公共方法(像上面的common方法),并且把函数式接口作为其入参,在具体业务实现中,使用lambda表达式实现具体业务实现(像上面的method1Operation、method2Operation)。
相关文章:
Java 函数式编程实例
一、函数式编程概念 函数式编程是一种编程的范式和编程的方法论(programming paradigm),它属于结构化编程的一种,主要的思想是把运算的过程尽量通过一组嵌套的函数来实现。 函数式编程的几个特点: 函数可以作为变量、参数、返回值和数据类…...
Ant design Chart onReady函数使用外部变量问题
一、问题描述封装了一个Chart组件,它接收一个boolean类型的props,根据这个boolean的true或false执行不同的操作。经过console.log验证,onReady函数只会在组件初次渲染时取到props值,不管后面的props变化成什么都无法重新取值。二、…...
Unity使用webSocket与服务器通信(一)搭建一个简单地服务器和客户端
你想在unity WebGL里面使用TCP通信吗,那么你可以用一用webSocket。当然,桌面端也可以使用webSocket,这样Unity多平台发布的时候,业务层的通信代码可以使用一套,而不是桌面用socket,网页用http… 一、什么是…...
SpringCloud微服务实战——搭建企业级开发框架(四十九):数据字典注解的设计与实现
数据字典是系统中基本的必不可少的功能,在多种多样的系统中,数据字典表的设计都大同小异。但是使用方式确是多种多样,设计好一套易用的数据字典功能模块,可以使开发事半功倍。 常用的数据字典使用方式: 直接在SQL语句…...
mysql下,实现保存指定用户、ip、命令的查询日志
环境:mysql 8.0.14 社区版 阅读文本需要的背景知识:对数据库的基本概念(触发器、存储过程、事件),mysql下general log的配置指令 背景:因审计需要,对于数据库操作需要留痕。实际访问数据库的有…...
Vue 3.0 学习笔记之基础知识
系列文章目录 提示:阅读本章之前,请先阅读目录 文章目录系列文章目录前言Vue 3.0 创建与Vue2.0对比的变化关闭语法检查setup 组合式函数compositions响应式数据 refreactive 函数Vue3.0 响应原理ref 和 reactive 区别setup 注意点computed 计算函数watch…...
WebGIS行政区炫酷特效——流光特效教程
先来看下效果: 图片截图: 流光特效的思路是从行政区的边界中随着时间不断的取若干段线条换成另一种高亮颜色。 流光的第一步首先是发光,发光的教程在这里: GIS矢量图形多边形地块行政区发光,阴影发光特效实现_疯狂的GISer的博客-CSDN博客 学会发光以后,接下来需要做的…...
2023-3-3 刷题情况
保证文件名唯一 题目描述 给你一个长度为 n 的字符串数组 names 。你将会在文件系统中创建 n 个文件夹:在第 i 分钟,新建名为 names[i] 的文件夹。 由于两个文件 不能 共享相同的文件名,因此如果新建文件夹使用的文件名已经被占用…...
《青浦区加快发展跨境电子商务实施细则(审议稿)》
为进一步贯彻落实《中华人民共和国电子商务法》,上海市《关于促进本市跨境电子商务发展的若干意见》,切实做好青浦区跨境电子商务试点工作,探索和规范跨境电子商务管理,促进跨境电子商务健康快速发展,青浦商务委根据多…...
【React全家桶】React生命周期
React生命周期 1、初始化阶段 componentDidMount:render之前最后一次修改状态的机会 render:只能访问this.props和this.state,不允许修改状态和DOM输出 componentDidMount:成功render并渲染完成真实DOM之后触发 2、旧生命周期 👉👉👉加…...
B. Count the Number of Pairs
原题链接 纯纯水一下; 昨天晚上的比赛,由于半夜打的,精神状态不好,wa了俩发直接睡觉去了,现在白天写写发现,不难,水中水 模拟题吧,题目怎么说就这么作 Kristina has a string ss…...
离线数据仓库项目--技术选择
文章目录(一)技术选型1)数据采集工具2)数据存储3)数据计算4)数据可视化(二)整体架构设计(三)服务器资源规划(一)技术选型 1ÿ…...
GC Garbage Collectors
本质一、算法1、哪些是垃圾?引用计数法:reference countPython中使用了。个对象如果没有任何与之关联的引用,即他们的引用计数都不为 0,则说明对象不太可能再被用到,那么这个对象就是可回收对象。漏洞:循环…...
【网络】-- 网络基础
(本文是网络的宏观的概念铺垫) 目录 计算机网络背景 网络发展 认识 "协议" 网络协议初识 协议分层 OSI七层模型 TCP/IP 五层(或四层)模型 报头 以太网 碰撞 路由器 IP地址和MAC地址 IP地址与MAC地址总结 IP地址 MAC地址 计算机…...
二、Redis安装配置(云服务器、vmware本地虚拟机)
一、自己购买服务器 自己购买阿里云、青牛云、腾讯云或华为云服务器, 自带CentoOS或者Ubuntu环境,直接开干 二、Vmware本地虚拟机安装 1、VMWare虚拟机的安装,不讲解,默认懂 2、如何查看自己的linux是32位还是64位 getconf L…...
【学习Docker(七)】详细讲解Jenkins部署SpringCloud微服务项目,Docker-compose启动
Jenkins部署SpringCloud微服务项目,Docker-compose启动 座右铭:《坚持有效输出,创造价值无限》 本文介绍使用Jenkins部署SpringCloud微服务项目,Docker-compose启动。 之前写过安装Jenkins的过程,这里就不写安装细节了…...
时机将至,名创优品或将再掀起一波消费热浪
北京时间2月28日,名创优品发布2023财年中报,财报显示,2023财年第二季度营收规模有所收窄,但净利润、毛利率、门店数量均实现了不错的增长,总体表现可圈可点。 (资料来源:富途牛牛) …...
深圳大学计软《面向对象的程序设计》实验8 静态与友元
A. 旅馆旅客管理(静态成员) 题目描述 编写程序,实现某旅馆的客人住宿记录功能。 定义一个Customer类,要求输入客人的姓名,创建一个Customer对象。类声明如下: 调用类的Display函数输出客人IDÿ…...
【基础算法】单链表的OJ练习(2) # 链表的中间结点 # 链表中倒数第k个结点 #
文章目录前言链表的中间结点链表中倒数第k个结点写在最后前言 对于单链表的OJ练习,需要深刻理解做题的思路,这样我们才能够在任何场景都能够熟练的解答有关链表的问题。 关于OJ练习(1):-> 传送门 <-,…...
vue路由文件拆分管理
随着项目的原来越大,路由越来越多,我们的路由也会越来越多,如果都集中在一个文件中,会很冗杂文件很长。这时候我们可以将路由文件拆分,可读、方便管理。多人合作添加路由也能更多的避免代码冲突 代码拆分目录如图&…...
实例解析Java反射
反射是大多数语言里都必不不可少的组成部分,对象可以通过反射获取他的类,类可以通过反射拿到所有方法(包括私有),拿到的方法可以调用,总之通过“反射”,我们可以将Java这种静态语言附加上动态特…...
Android 9适配经验总结
目录四大组件适配Activity启动方式适配Service启动方式适配前台服务需要添加权限限制静态广播的接收限制ContentResolver数据更新操作权限与安全相关主要适配点运行时动态权限申请默认不支持 http 请求SharedPreferences 适配四大组件适配 Android 应用的开发离不开 Android 四…...
定时任务调度方案——Xxl-Job
定时任务调度方案 随着系统规模的发展,项目的组织结构以及架构越来越复杂,业务覆盖的范围越来越广,定时任务数量日益增多,任务也变得越来越复杂,尤其是为了满足在用户体量日历增大时,系统能够稳定运行&…...
操作系统引导
操作系统是一种程序,程序以数据的形式存放在硬盘中,而硬盘通常分为多个区,一个计算机中又有多个或多种外部设备。 操作系统引导指的是计算机利用CPU运行特定程序,通过程序识别硬盘,识别硬盘分区,识别硬盘分…...
[C#] 多线程单例子,分为阻塞型和分阻塞型, 在unity里的应用
在单例中使用多线程时,需要注意以下几点: 线程安全:在多线程环境下,单例对象可能被多个线程同时访问,因此需要确保单例的线程安全,避免出现数据竞争等问题。 对象创建:如果在单例对象的构造函数…...
使用MAT进行内存分析,并找到OOM问题
前言 在处理一次现场问题时,发现服务还在运行,但是出现假死情况,后通过分析GC日志以及使用MAT分析确定问题是内存溢出OutOfMemery(OOM);这里只记录MAT分析学习过程,最近工作忙,补记录。 GC日志分析 首先,如…...
初识Python
目录初识Python1.Python简介Python的优缺点Python的应用领域2.安装Python解释器Windows环境Linux环境macOS环境3.运行Python程序确认Python的版本编写Python源代码运行程序代码中的注释4.Python开发工具IDLE - 自带的集成开发工具IPython - 更好的交互式编程工具Sublime Text -…...
tmux终端复用软件
一、安装[rootpool-100-1-1-159 test]# yum install tmux [rootpool-100-1-1-159 test]# yum search tmux Repository extras is listed more than once in the configuration Last metadata expiration check: 0:33:52 ago on Fri 03 Mar 2023 09:10:34 AM CST.Name Exactly M…...
IO详解(文件,流对象,一些练习)
目录 文件 文件概念 文件的路径 路径有俩种表示风格 文件类型 如何区分文本文件还是二进制文件? java对文件的操作 File类中的一些方法 流对象 流对象的简单概念 java标准库的流对象 1.字节流,(操作二进制数据的) 2.字符流 (操作文本数据的) 流对象最核心的四个…...
SpringCloud全家桶— — 【1】eureka、ribbon、nacos、feign、gateway
SpringCloud全家桶— — 组件搭建 1 Eureka 1.1 Eureka-server 创建eureka-server的SpringBoot项目 ①导入依赖 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId…...
wordpress官方安装主题/营销策划是做什么
有关BOM的详细属性和方法请参阅相关文档,这里只列举常用的属性和方法,不做其他赘述。 window window表示浏览器的一个实例。它既是通过JavaScript访问浏览器窗口的一个接口,又是ECMAScript规定的global对象。所有在全局作用域声明的变量和函数…...
郑州网站建设开拓者/谷歌推广开户多少费用
HTML DOM 访问访问 HTML DOM - 查找 HTML 元素。访问 HTML 元素(节点)访问 HTML 元素等同于访问节点您能够以不同的方式来访问 HTML 元素:通过使用 getElementById() 方法通过使用 getElementsByTagName() 方法通过使用 getElementsByClassName() 方法getElementByI…...
wordpress安装模版500/如何做网页设计
一、官网下载: 先去官网下载安装包: postman的官网 二、下载后,创建安装包,postman会自动安装成功。直接打开即可。 三、如果没有账号,退出再次登录即可...
陕西 做网站的公司/win7优化工具哪个好用
GDI绘图基础 编写图形程序时需要使用GDI(图形设备接口Graphics Device Interface),从程序设计的角度看,GDI包括两个部分:GDI对象和GDI函数。 GDI对象定义了GDI函数使用的工具和环境变量,GDI函数对象绘制各…...
想学网站制作/太原seo团队
STM32Cube 串口DMA发送问题:只能运行一次,第二次返回状态为HAL_BUSY 解决办法: 这样就可以实现每次调用HAL_UART_Trasmit_DMA发送指定长度的数组。转载于:https://www.cnblogs.com/zq-Embedded-System/p/5925714.html...
双流规划建设管理局网站/爱站网关键词查询网站的工具
一、 数据库的导出(expdp)1.创建默认导出目录SQL>create directory [dirname] as ‘[dirpath]’;2.赋予指定用户在此目录的读写权限SQL>GRANT READ, WRITE ON DIRECTORY [dirname] to [dbuser];3.使用expdp导出数据库① 导出完整schema> expdp [username/passwd]DUMPF…...