Java8,函数式编程应用:

news2024/9/22 13:36:06

持续更新中:

函数式(Functional)接口 什么是函数式(Functional)接口 只包含一个抽象方法的接口,称为函数式接口。

你可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda 表达式
抛出一个受检异常(即:非运行时异常),那么该异常需要在目标接口的抽 象方法上进行声明)。

我们可以在一个接口上使用 @FunctionalInterface 注解,这样做可以检 查它是否是一个函数式接口。同时 javadoc
也会包含一条声明,说明这个 接口是一个函数式接口。

在java.util.function包下定义了Java 8 的丰富的函数式接口:

package com.ly.frauddataplatform.luoyan;

//TODO: 需要在接口上定义@FunctionalInterface注解,表示这是一个函数式的接口
//TODO: MyFunc<R,T>这里是标明泛型
@FunctionalInterface
public interface MyFunc<R,T> {
    /**
     * @Author luoyan
     * @Description: 函数式编程
     * @Date 2024/3/4 20:42
     * @param t: 入参,泛型可以传任何类型
     * @return R: 返回参数,泛型可以传任何类型
    **/
    R getValue(T t);
}

这里是自定义的函数式编程的自定义的实现接口方式:

    //TODO: 这里自定义一个方法,这个方法可以实现前置通知,后置通知,可以在调用方法的前后做一些公用的操作.
    //TODO: 在调用到自己的实现方法中的时候,去设计实现自己所需要的代码逻辑流程.
    /**
     * @Author luoyan
     * @Description: 封装的方法,泛型中<R,T>:这个是声明泛型,R:返回的类型,也可以修改R为String,T为String.那么入参和出现就必须是String的类型.
     * @Date 2024/3/4 20:46 
     * @param myFunc: 这个是函数方法
     * @param name: 入参
     * @return R
    **/
    public <R,T> R toUpDate(MyFunc<R, T> myFunc, T name){
        System.out.println("前置通知");
        //TODO: 调用自己设定订代码逻辑流程.
        R value = myFunc.getValue(name);
        System.out.println(value);
        System.out.println("后置通知");
        return myFunc.getValue(name);
    }
    
    //TODO: 使用一个方法进行测试.
    @Test
    public void testDemoOne(){
        //TODO: 这里实现自己的代码逻辑.
        //TODO: 这里name是T,也就是入参,"1231"是R,也就是出参,可以自己随意定义,因为是泛型.
        String s = toUpDate(str -> {
            System.out.println(str);
            return "1231";
        }, true);
        
        System.out.println(s);
    }

Predicate:函数接口

Predicate<Integer> predicate = n ->{
    if (n > 4){
        return true;
    }
    return false;
};

Predicate<Integer> and = predicate.and(k -> {
    if (k < 6) {
        return true;
    }
    return false;
}).or(t -> {
    if (t == 10) {
        return true;
    }
    return false;
});
boolean test1 = and.test(5);
System.out.println(test1);

在这里插入图片描述

这里使用:Function接口来实现。此接口的特点:有入参,有出参,可以直接很好的使用。还有其他的函数。
在这里插入图片描述
比如:只需要入参,不需要出参,可以根据自己的情况而定。
在这里插入图片描述

举一个例子:
比如我们要使用前置要做的事情,然后调用方法自己的逻辑,最后在执行一个后置要做的事情,其中前置流程和后置流程都是共有的流程。那么就可以使用函数式的变成去封装方法,然后每个地方都可以直接调用。这样很方便。

如果没有函数式编程,我们可能会想到反射的方式,传入一个类,一个方法,然后通过反射的方式去调用这个类中的某个方法,从而可以达到这种实现,但是太麻烦了。

目前我们需要对于redis进行上锁,然后解锁,中间是走自己的流程,那么我们就可以使用函数式编程:

package com.elong.fraud.rcenginedataconvert.constants;

import com.elong.fraud.rcenginedataconvert.model.dto.TryLockParamData;
import com.ly.tcbase.cacheclient.CacheClientHA;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.UUID;
import java.util.function.Function;

/**
 * @Author luoyan
 * @Description: redis锁
 * @Date 2024年01月18日 10:38
 * @Version: V1.0
 */
@Component
public class RedissionTemplate {

    @Resource
    private CacheClientHA cacheClientHa;

    /**
     * @Author luoyan
     * @Description:
     * @Date 2024/1/19 15:15
     * @param tryLockParamData: 入参值.
     *                        LockKey:key,
     *                        param:请求参数
     * @param consumer: Function<T,R> 
     *                T:入参,
     *                R:返回参数
     * @return R
    **/
    public <R> R tryLock(TryLockParamData tryLockParamData, Function<Object,R> consumer){
        //TODO: 前置通知,对于参数进行校验
        String lockKey = tryLockParamData.getLockKey();
        if (ObjectUtils.isEmpty(lockKey)){
            return null;
        }
        //TODO: 前置通知,进行上锁
        String lockVal = UUID.randomUUID().toString();
        Boolean lock = cacheClientHa.String().setnx(lockKey, 60L, lockVal);
        try {
            long millis = System.currentTimeMillis();
            while (!lock) {
                //等待锁释放
                try {
                    if (System.currentTimeMillis() - millis > 3000) {
                        throw new RuntimeException("程序异常,未获取锁!");
                    }
                    Thread.sleep(100);
                } catch (Exception ignore) {
                }
                lock = cacheClientHa.String().setnx(lockKey, 60L, lockVal);
            }
            //TODO: 这里去调用自己的代码流程
            return consumer.apply(tryLockParamData.getParam());
        }finally {
            //TODO: 后置通知,去进行解锁。
            if (lockVal.equals(cacheClientHa.String().setcas(lockKey, lockVal, lockVal))) {
                cacheClientHa.Key().del(lockKey);
            }
        }
    }
}

第一处调用:

private JSONObject saveOrUpdateOriginData(JSONObject newValue, String uniqueId, String sourceName) {
    //分布式锁
    String lockKey = String.format(RedisCacheConstants.DATA_SOURCE_DETAIL_LOCK_FORMAT, sourceName, uniqueId);
    //TODO:new TryLockParamData(lockKey):入参。逗号后面就是函数方法,也就是自己的代码逻辑。
    JSONObject newValReturn = redissionTemplate.tryLock(new TryLockParamData(lockKey), consumer -> {
		//TODO: 自己的代码逻辑流程,先上锁,然后走这里的代码逻辑流程,最后进行解锁。
        return newVal;
    });
    return newValReturn == null ? new JSONObject() : newValReturn;
}

第二处调用:

//分布式锁
String lockKey = String.format(RedisCacheConstants.FEATURE_LIST_UPDATE_LOCK_FORMAT, uniqueId);
//TODO:new TryLockParamData(lockKey):入参。逗号后面就是函数方法,也就是自己的代码逻辑。
redissionTemplate.tryLock(new TryLockParamData(lockKey), rLock -> {
	//TODO: 自己的代码逻辑流程,先上锁,然后走这里的代码逻辑流程,最后进行解锁。
    //先执行更新,更新失败执行插入
    int update = dcdbFraudMapper.update(origin.getTableName(), fieldList, StrUtil.toUnderlineCase(origin.getUpdateKey()), uniqueId);
    if (update == 0) {
        boolean insert = dcdbFraudMapper.insert(origin.getTableName(), fieldList);
    }
    return null;
});

可以看到上面两处的调用使用函数式编程非常方便且代码也很美观,不用其他的方式就能够快速的实现,对于同事的阅读和理解也是非常快速的。

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

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

相关文章

Linux学习:初识Linux

目录 1. 引子&#xff1a;1.1 简述&#xff1a;操作系统1.2 学习工具 2. Linux操作系统中的一些基础概念与指令2.1 简单指令2.2 ls指令与文件2.3 cd指令与目录2.4 文件目录的新建与删除指令2.5 补充指令1&#xff1a;2.6 文件编辑与拷贝剪切2.7 文件的查看2.8 时间相关指令2.9 …

为什么TestNg会成为Java测试框架的首选?还犹豫什么,看它!

上一篇自动化测试我们大概了解了测试的目标、测试的技术选型以及搭建平台的目标及需求&#xff0c;也确定了自动化测试方案以testNg作为整个测试流程贯穿的基础支持框架&#xff0c;那么testNg究竟有什么特点&#xff1f;本篇开始我们来详细的学习testNg这个测试框架。 为什么要…

软件设计师8--输入输出技术

软件设计师8--输入输出技术 考点1&#xff1a;输入输出技术数据传输控制方式中断处理过程例题&#xff1a; 考点1&#xff1a;输入输出技术 数据传输控制方式 √ 程序控制&#xff08;查询&#xff09;方式&#xff1a;分为无条件传送和程序查询方式两种。方法简单&#xff0…

MySQL篇—执行计划之覆盖索引Using index和条件过滤Using where介绍(第三篇,总共三篇)

☘️博主介绍☘️&#xff1a; ✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ ✌✌️擅长Oracle、MySQL、SQLserver、Linux&#xff0c;也在积极的扩展IT方向的其他知识面✌✌️ ❣️❣️❣️大佬们都喜欢静静的看文章&#xff0c;并且也会默默的点赞收藏加关注❣…

python实现手机号归属地查询

手机上突然收到了某银行的短信提示&#xff0c;看了一下手机的位数&#xff0c;正好是11位。我一想&#xff0c;这不就是标准的手机号码吗&#xff1f;于是一个想法涌上心头——用python的库实现查询手机号码归属地查询自由。 那实现的效果如下&#xff1a; 注&#xff1a;电…

yolov7添加spd-conv注意力机制

一、spd-conv是什么&#xff1f; SPD-Conv&#xff08;Symmetric Positive Definite Convolution&#xff09;是一种新颖的卷积操作&#xff0c;它主要应用于处理对称正定矩阵&#xff08;SPD&#xff09;数据。在传统的卷积神经网络&#xff08;CNN&#xff09;中&#xff0c;…

【java数据结构】模拟二叉树的链式结构之孩子表示法,掌握背后的实现逻辑

&#x1f4e2;编程环境&#xff1a;idea &#x1f4e2;树结构&#xff0c;以及叶子&#xff0c;结点&#xff0c;度等一些名词是什么意思&#xff0c;本篇不再赘述。 【java数据结构】模拟二叉树的链式结构之孩子表示法&#xff0c;掌握背后的实现逻辑 1. 认识二叉树1.1 二叉树…

桂院校园导航 | 云上高校导航 云开发项目 二次开发教程 2.0

Gitee代码仓库&#xff1a;桂院校园导航小程序 GitHub代码仓库&#xff1a;GLU-Campus-Guide 演示视频 【校园导航小程序】2.0版本 静态/云开发项目 演示 云开发项目 2.0版本 升级日志 序号 板块 详情 1 首页 重做了首页&#xff0c;界面更加高效和美观 2 校园页 新增…

Python判断结构20个实例

基本理论基础 Python中的选择判断结构是一种编程中常用的控制结构&#xff0c;它用于根据条件的真假决定程序的执行路径。选择判断结构有多种类型&#xff0c;包括if语句、if-else语句、if-elif-else语句以及嵌套的选择结构。 首先&#xff0c;我们来介绍最常见的if语句。if语…

浅谈WPF之Binding数据校验和类型转换

在WPF开发中&#xff0c;Binding实现了数据在Source和Target之间的传递和流通&#xff0c;就像现实生活中的一条条道路&#xff0c;建立起了城镇与城镇之间的衔接&#xff0c;而数据校验和类型转换&#xff0c;就像高速公路之间的收费站和安检站。那在WPF开发中&#xff0c;如何…

引入本地图片报错:require is not defined

文章目录 问题分析1. 原始写法2. 最初的解决方案3. 尝试使用 require 引入4. 封装方法进行解析引入图片 问题 Vue3 Vite 使用本地图片报错&#xff1a;require is not defined 分析 1. 原始写法 刚开始我是这样写的&#xff0c;数据是这样定义的&#xff0c;但是数据没出…

Vue.js+SpringBoot开发高校实验室管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 实验室类型模块2.2 实验室模块2.3 实验管理模块2.4 实验设备模块2.5 实验订单模块 三、系统设计3.1 用例设计3.2 数据库设计 四、系统展示五、样例代码5.1 查询实验室设备5.2 实验放号5.3 实验预定 六、免责说明 一、摘…

2024年R2移动式压力容器充装证考试题库及R2移动式压力容器充装试题解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年R2移动式压力容器充装证考试题库及R2移动式压力容器充装试题解析是安全生产模拟考试一点通结合&#xff08;安监局&#xff09;特种作业人员操作证考试大纲和&#xff08;质检局&#xff09;特种设备作业人员上…

快速幂(求解原理+例题)

目录 反复平方法&#xff08;快速幂&#xff09;&#xff1a; 代码&#xff1a; 例题&#xff1a;快速幂求逆元 作用&#xff1a; 快速求出 的结果。 时间复杂度&#xff1a; O(logk) 如果使用一般做法&#xff0c;从1循环到k&#xff0c;时间复杂度是O(k) 反复平方法&am…

倒计时35天

小红的子序列权值和 (nowcoder.com) #include<bits/stdc.h> using namespace std; #define int long long const int N2e56; const int inf0x3f3f3f3f; const double piacos(-1.0); const int mod1e97; int c[1100][1100]; int a[1100],b[5]; void solve() {int n;cin>…

照片变年轻怎么操作?收好这几个方法

照片变年轻怎么操作&#xff1f;在这个数字时代&#xff0c;我们手中的智能手机和相机成为了记录生活的重要工具。然而&#xff0c;随着时间的推移&#xff0c;照片中的人物往往会因为岁月的痕迹而显得苍老。那么&#xff0c;有没有一种方法可以让这些珍贵的回忆重新焕发青春呢…

[DevOps云实践] 跨AWS账户及Region调用Lambda

[DevOps云实践] 跨AWS账户及Region调用Lambda 本文將幫大家理清一下幾個問題: 如何跨不同AWS賬戶,不同Region來調用Lambda? 不同Lambda之間如何互相調用?有時我們希望我們的Lambda脚本能夠運行在多個AWS賬戶中的不同Region下,但是,我們還不希望每個下面都去建立一個運行…

从0开始学习NEON(1)

1、前言 在上个博客中对NEON有了基础的了解&#xff0c;本文将针对一个图像下采样的例子对NEON进行学习。 学习链接:CPU优化技术 - NEON 开发进阶 上文链接:https://blog.csdn.net/weixin_42108183/article/details/136412104 2、第一个例子 现在有一张图片&#xff0c;需…

【CSP试题回顾】201403-2-窗口

CSP-201403-2-窗口 解题思路 窗口存储结构&#xff1a;首先&#xff0c;使用一个结构体MyWindow来存储每个窗口的信息&#xff0c;包括窗口的序号&#xff08;index&#xff09;和矩形区域的四个顶点坐标&#xff08;x1, y1, x2, y2&#xff09;。所有窗口的信息存储在一个向量…

17 easy 290. 单词规律

//给定一种规律 pattern 和一个字符串 s &#xff0c;判断 s 是否遵循相同的规律。 // // 这里的 遵循 指完全匹配&#xff0c;例如&#xff0c; pattern 里的每个字母和字符串 s 中的每个非空单词之间存在着双向连接的对应规律。 // // // // 示例1: // // //输入: patte…