泛型方法、Function类的函数化编程与调用

news2024/11/27 15:27:55

0、引言

        在项目开发的过程中,常常需要将一些高频复用的方法封装成工具类,例如最近学到的Redis缓存中,解决缓存穿透、解决缓存击穿的方法(例如解决缓存穿透的问题的方法queryWithPassThrough),传入一个Long型id,返回你要查询的数据。

        问题在于,queryWithPassThrough方法不能指定一种返回类型,比如店铺类型、人员类型、评论类型等等各种类型,作为工具类,我们希望它能够随着调用而返回对应的类型

        因此,需要使用泛型方法来完成这个需求。

1、泛型方法的区分与定义

定义:

        在确定某个方法是否为泛型方法时,需要判断其是否声明了类型参数,类型参数的作用域是在方法内还是在整个泛型类中。

        如果只涉及到特定方法操作的类型参数,则该方法是泛型方法;如果类型参数定义在泛型类中,则不论它们是否被方法使用,该方法都不是泛型方法。

举例:        

        例如, 按照上述原则,用以下例子method0、1、2进行说明:       

class a<T,M>{
    T t;
    M m;

    public void method0(T t,M m){
        //不是泛型方法,仅仅是用了泛型类的标识符
        System.out.println(t.getClass());
        System.out.println(m.getClass());
        System.out.println("====================");
    }
    public<S,U>void method1(S s,U u){
        System.out.println(s.getClass());
        System.out.println(u.getClass());
        System.out.println("====================");
    }//是泛型方法,根据传入的参数自己规划数据类型

    public<K>void method2(K k,M m){
        //k来自于泛型方法,而m是泛型类的标识符,但因为有K
        //因此也是泛型方法
        System.out.println(k.getClass());
        System.out.println(m.getClass());
    }
}
  1. method0 方法的类型参数 T 和 M 都是定义在实例变量上的泛型类型,它们只在泛型类中使用,而不涉及方法的特定操作。因此,method0 不是泛型方法。

  2. method1 方法声明了一个类型参数 S 和一个类型参数 U,这些参数只在该方法中使用。由于它们是方法级别的,所以 method1 是泛型方法。

  3. method2 方法声明了一个类型参数 K,它只在该方法中使用,所以 method2 是泛型方法。但是,方法中的参数 M 是泛型类的类型参数,因此也可以用在泛型方法中。

2、使用泛型方法实现自适应返回类型

 public <R,ID> R queryWithPassThrough(
String keyPrefix, ID id, Class<R> type, 
Function<ID, R> dbFallback, 
Long time, TimeUnit unit)

        例如上述方法,是防止缓存穿透的方法定义,<R,ID>是定义的两个泛型,R类型是这个方法的返回类型(即实际要查询的数据类型),通过函数式编程Function函数,来实现查询ID类型的id所对应的数据类型R的数据。

        这里将介绍一下:(1)Function函数的使用。(2)用反射实现返回指定类型数据

2.1 Function函数的使用

        由于具体的查询语句可能是变化的,因此,“具体怎么查”,这个查询函数不是定死的,作为工具类也不能把它写死,而是采用函数式编程的方法:
        即,要用什么函数查询,就传入什么函数。

Funtion的使用方法与底层原理:

        从源码看,对于Function接口,其内部存在一个apply方法:

        对于第二章开头的代码,内部调用:     

        R r = dbFallback.apply(id);

        在本例中:applyFunction 接口中定义的抽象方法,用于接受一个参数并返回一个结果。在 Function<ID, R> 中,apply 方法接受一个类型为 ID 的参数,返回一个类型为 R 的结果。

        因此,我们只需要重写这个apply方法,变成我们想要使用的方法即可!

        在以上的基础上如果想要调用函数,可以使用lambda表达式,传入id->getById(id),则相当于:

Function<ID, R> dbFallback = id -> getById(id);
//或者:
Function<ID, R> dbFallback = this::getById;

//可能有的人对lambda语法不熟悉,其实就是使用了匿名内部类的方式实现apply方法:
//即:
Function<ID, R> dbFallback = new Function<>(){
    @Override
    public R apply(ID id){
        return getById(id);
    }
}

  在调用时的语句就可以这么写:      

Shop shop = cacheClient
        .queryWithPassThrough(CACHE_SHOP_KEY, id, Shop.class, id->getById(id), CACHE_SHOP_TTL, TimeUnit.MINUTES);

        在实际上,我们想传入什么方法来进行查询都可以(想怎么实现apply都可以),从而实现了函数式编程。

2.2 用反射实现返回类型的变化

 public <R,ID> R queryWithPassThrough(String keyPrefix, ID id, Class<R> type, 
Function<ID, R> dbFallback, Long time, TimeUnit unit)

        在以上的方法定义下,编写具体查询代码的时候发现:从Redis里get得到的数据时json字符串格式的,但是我们想要的是任意的“R”型,比如商店类的Shop类型,等类型,该怎么办呢?

        String key = keyPrefix + id;
        // 1.从redis查询商铺缓存
        String json = stringRedisTemplate.opsForValue().get(key);
        // 2.判断是否存在
        if (StrUtil.isNotBlank(json)) {
            // 3.存在,直接返回
            return JSONUtil.toBean(json, type);
        }

        这里可以采用反射的方法:使用JSONUtil类中的toBean方法:

        传入:Shop.class即可,就会通过这个toBean进行转换。

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

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

相关文章

谷粒商城:Oss endpoint can‘t be empty.问题

商品API &#xff0c;文件上传管理的时候 出现这个问题 解决两个方向 1.springBoot、alibabaCloud、springCloud、aliyunOSS 之间的版本问题&#xff0c;我的是下面的版本可以运行了。 // springBoot版本 2.7.7 <groupId>org.springframework.boot</groupId> &l…

中关村论坛 | 金融业从增量到存量博弈背后两大原因 更重要的是……

在数字经济浪潮下&#xff0c;中国金融业正在经历数字化转型的深刻变革。为研判金融科技行业发展趋势和前景&#xff0c;探索金融创新与监管安全的边界&#xff0c;“2023中关村论坛金融科技论坛”于5月29日召开。 中电金信常务副总经理冯明刚与中国银行软件中心副总经理康钧伟…

链表:虚拟头节点你会用吗?

大家好&#xff0c;我是三叔&#xff0c;很高兴这期又和大家见面了&#xff0c;一个奋斗在互联网的打工人。 前言&#xff1a;什么是链表 什么是链表&#xff0c;链表是一种通过指针串联在一起的线性结构&#xff0c;每一个节点由两部分组成&#xff0c;一个是数据域一个是指…

提高用户忠诚度的 4 种客户保留策略

什么是客户保留&#xff1f;简而言之&#xff0c;客户保留是指企业用来鼓励现有客户群重复购买和持续忠诚度的策略和战术。根据最近的研究&#xff0c;多达68%的客户在觉得公司不重视他们的业务时会转向竞争对手。 这就是为什么客户保留对各行各业的企业都如此重要的原因。与获…

《程序员面试金典(第6版)》面试题 16.25. LRU 缓存(自定义双向链表,list库函数,哈希映射)

题目描述 设计和构建一个“最近最少使用”缓存&#xff0c;该缓存会删除最近最少使用的项目。缓存应该从键映射到值(允许你插入和检索特定键对应的值)&#xff0c;并在初始化时指定最大容量。当缓存被填满时&#xff0c;它应该删除最近最少使用的项目。 题目传送门&#xff1a;…

消息队列内容

问题有哪些&#xff1f; &#xff08;1&#xff09;消息队列为什么会出现&#xff1f; &#xff08;2&#xff09;消息队列能用来干什么&#xff1f; &#xff08;3&#xff09;使用消息队列存在的问题&#xff1f; &#xff08;4&#xff09;如何解决重复消费的问题&#…

PyCharm安装使用教程

简介 PyCharm是一种PythonIDE&#xff08;Integrated Development Environment&#xff0c;集成开发环境&#xff09;&#xff0c;带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具&#xff0c;比如调试、语法高亮、项目管理、代码跳转、智能提示、自动完成、单…

docker-安装redis集群

目录 1.服务器列表 2.安装docker 3.docker内网IP地址配置 4.docker安装redis集群 1.选择合适数据位置 2.循环生成redis配置目录 3.打开宿主机防火墙端口 4.循环生成redis容器 5.创建集群命令 6.命令行集群验证 1.服务器列表 服务器列表 nameip远程端口用户名/密码cen…

One2Multi Graph Autoencoder for Multi-view Graph Clustering

One2Multi Graph Autoencoder for Multi-view Graph Clustering | Proceedings of The Web Conference 2020 (acm.org) 目录 Abstract 1 Introduction 2 Model 2.1 Overview 2.2 One2Multi Graph Convolutional Autoencoder Informative graph convolutional encoder M…

Eclipse教程 Ⅸ

今天继续来学习Eclipse 快速修复、Eclipse 浏览菜单、Eclipse 查找以及Eclipse 悬浮提示的内容&#xff01;老规矩&#xff0c;废话不多说&#xff0c;开始吧。 Eclipse 快速修复 使用快速修复 在 Eclipse 编辑器中当你输入字母时&#xff0c;编辑器会对你输入的内容进行错误…

PostgreSQL FDW

一、FDW简单理解 FDW (foreign-data wrapper&#xff0c;外部数据包装器)&#xff0c;PostgreSQL FDW 是一种外部访问接口&#xff0c;它可以被用来访问存储在外部的数据&#xff0c;这些数据可以是外部的pg数据库&#xff0c;也可以oracle、mysql等数据库&#xff0c;甚至可以…

大气气溶胶期末复习笔记

大气气溶胶期末复习笔记 大气气溶胶 广义&#xff1a;指悬浮在大气中的各种固态和液态微粒与大气构成的混合体系 狭义&#xff1a;指大气中悬浮的各种固态粒子&#xff0c;简称气溶胶粒子 来源 直接注入 通过地表直接注入大气固体&#xff0c;液体物质的破碎过程中产生&…

筛质数—(埃氏筛欧拉筛)

埃氏筛&欧拉筛 埃氏筛欧拉筛 例题&#xff1a;AcWing 868. 筛质数 对欧拉筛的理解不是很深刻&#xff0c;写下自己的理解&#xff0c;加深一下理解&#xff0c;也方便后期忘记后再学习 埃氏筛 埃氏筛的主要思想是让质数x去筛掉x的所有合数&#xff0c;这个比较容易理解。…

机器学习知识经验分享之五:R语言安装

python语言用于深度学习较为广泛&#xff0c;R语言用于机器学习领域中的数据预测和数据处理算法较多&#xff0c;后续将更多分享机器学习数据预测相关知识的分享&#xff0c;有需要的朋友可持续关注&#xff0c;有疑问可以关注后私信留言。 目录 一、R语言介绍 二、R语言安装…

装饰器模式:实现类功能的动态扩展

一&#xff0c;简介 装饰器模式&#xff08;Decorator Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许在不修改原有类结构的情况下&#xff0c;给一个对象动态添加额外的职责。通常情况下&#xff0c;扩展一个类的功能我们首先会想到用继承方式来实现&#xff0c…

7步搞懂手写数字识别Mnist

大家好啊&#xff0c;我是董董灿。 图像识别有很多入门项目&#xff0c;其中Mnist 手写数字识别绝对是最受欢迎的。 该项目以数据集小、神经网络简单、任务简单为优势&#xff0c;并且集合了CNN网络中该有的东西&#xff0c;可谓麻雀虽小&#xff0c;五脏俱全。 非常适合新手…

Fourier分析入门——第12章——Fourier变换的性质

目录 第12章 Fourier变换的性质 12.1 引言 12.2 Fourier变换性质的相关定理 12.2.1 线性定理(Linearity) 12.2.2 伸缩性定理(Scaling) 12.2.3 时间/空间平移定理(Shift) 12.2.4 频移定理 12.2.5 调制定理(Modulation) 12.2.6 微分定理(Differentiation) 12.2.7 积分定…

冒泡排序详解(Bubble Sort)

本文已收录于专栏 《算法合集》 目录 一、简单释义1、算法概念2、算法目的3、算法思想4、算法性质 二、核心思想构建排序 三、图形展示宏观展示微观展示 四、算法实现实现思路代码实现客户端调用构造堆的方法元素交换的方法元素比较的方法 运行结果 五、算法描述1、问题描述2、…

数据库管理-第七十八期 记第一次数据库吐槽大会(20230530)

数据库管理 2023-05-30 第七十八期 记第一次数据库吐槽大会1 主席2 三六九等3 数据库吐槽大会总结 第七十八期 记第一次数据库吐槽大会 昨天晚上终于还是把Exadata X9M-2和之前用于展示RAC搭建及升级的那套库做好了ADG&#xff0c;这部分操作在整理后会在下个月发出来。因为之…

Python列表类型的使用

文章目录 Python中的列表类型一、列表的常用操作二、列表的增删改查三、列表常用的函数 Python中的列表类型 将各个元素用方括号&#xff08;[]&#xff09;括起来&#xff0c;用逗号&#xff08;,&#xff09;分隔开&#xff0c;这种形式的数据类型就是列表。各个元素的数据类…