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

kotlin高阶函数

kotlin高阶函数

函数式API:一个函数的入参数为Lambda表达式的函数就是函数式api
例子:

public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {return filterTo(ArrayList<T>(), predicate)
}

上面这段函数: 首先这个函数是一个泛型函数
泛型函数的定义:就是我们在写完一个函数后,只知道一个总的类型,而这个总的类型下有很多继承了这个总类型的类,在返回时我们不知道这个函数具体返回哪个子类,这时我们就可以在这个函数前面加一个泛型,泛型中放这些子类的基类,上面的filter方法也可以看作 Iterable的扩展方法

例子:

// A为基类
public class A{}
public class  B extends A{}public class  C extends A{}	

// 我们不知道下面这个方法具体返回A,B,C到底哪一个类型时,因为类B和C继承自A,这时我们就可以将这个返回类型指定为基类型A

public static <A> test(){}

下面我写kotlin的写法

class ReportV2Controller : Controller(){
}

和上面java一样有多个类继承自Controller()这个类,kotlin中继承都是以函数的形式,因为这样写直观的表现了自类具体会调用基类的哪个构造函数

	public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {return filterTo(ArrayList<T>(), predicate)
}		

上面的filter方法是迭代集合Iterable,但是在kotlin中这个Iterable是一个被inline修饰的内联函数

内联函数的出现的原因:
1.首先在kotlin中有高阶函数的原因,因为高阶函数的传参可以是一个函数,而且出参也可以为一个函数

// 下面这段代码原作者为csdn: Mr YiRan
fun num1AndNum2(num1:Int,num2:Int,operator:(Int,Int)->Int):Int{val result=operator(num1,num2)return result
}

上面这段代码高阶函数num1AndNum2入参为两个Int类型与一个函数类型operator,这个operator又接收两个int类型的参数,这个operator返回类型为int,operator返回的类型int同时也是num1AndNum2高阶函数的返回类型,同时num1AndNum2函数的入参数,也可以当作函数operator的入参

fun num1AndNum2(num1:Int,num2:Int,operator:(Int,Int)->Int):Int{val result=operator(num1,num2)return result
}// 定义两个具体的运算函数
fun plus(num1: Int,num2: Int):Int{
return num1+num2   
}
fun minus(num1: Int,num2: Int):Int{return num1-num2
}fun main(){val num1=100val num2=80// 这是一个函数引用方式的写法,表示将plus()和minus()函数作为参数传递给num1AndNum2()函数val result1= num1AndNum2(num1,num2,::plus)val result2 = num1AndNum2(num1, num2, ::minus)println("result1 is $result1")println("result2 is $result2")
}fun main(){
val num1=100
val num2=80
// 上面的函数引用写法的调用可以改为Lambda表达式的方式来调用高阶函数
val result1=num1AndNum2(num1,num2){ n1,n2 ->
n1+n2
}
val result2=num1AndNum2(num1,num2){ n1,n2 ->
n1-n2
}
println("result1 is $result1")
println("result2 is $result2")
}

Lambda表达式的优点与缺点

优点 :
如果一个抽象类或者接口中只有一个方法,我们又不想实例化这个类的对象就想调用这个方法,而且也不想将这个类中的方法标记为静态的方法,就可以用匿名内部类的方式类写,但是这样写代码很不美观,所以就简化成Lambda表达式的方式来写

缺点:
Lambda表达式的方式,系统会默认实例化一个匿名内部类的方式,就会造成额外的内存开销与cpu性能损耗
因为就算高阶函数中的传参写成Lambda表达式的方式,其内部运行顺序也为先实例化最外层类的对象,然后通过对象去引用当前这个对象的方法,将当前对象的方法存入方法区进行压栈然后再实例化一个Lambda表达式的匿名内部类,再通过这个对象去引用这个匿名内部类中的方法,再进行压榨

kotlin是如何解决这种因为传入Lambda表达式写法的性能开销的

内联函数

在定义高阶函数时加上inline关键字,就表示此高阶函数是一个内联函数

inline fun num1AndNum2(num1:Int,num2:Int,operation:(Int,Int)->Int):Int{
val result=operation(num1,num2)
return result
}

如何消除 Lambda表达式额外开销
简单来说就是:在调用传参为 Lambda表达式的高阶函数时,将 Lambda表达式的函数体直接拷贝在调用参数为 Lambda表达式的高阶函数后方
示例
在这里插入图片描述
在这里插入图片描述
1.首先将 Lambda表达式的入参拷贝到函数类型参数的参数入参列表中
2.其次再将内联函数的方法体拷贝到调用该高阶函数的地方
3.总结为:将实例化匿名内部类调用方法压栈改为方法入参数拷贝和方法体拷贝的过程

下面给一个返回值是一个函数的高阶函数
示例

/**

  • 定义一个返回值是函数的高阶函数
  • @param name 入场
  • @return 返回一个函数或者lambda
    */
    fun highFunction2(name:String):(Int) -> Int{
    if (name == “A”){
    // 这里返回一个函数引用,意思调用returnFun函数
    // 上面的highFunction2函数入参为两个一个String类型的name,还有一个入参是一个参数为一个int类型的Lambda表达式
    // 如果想调用returnFun函数那highFunction2函数传入的Lambda表达式入参类,数量与顺序必须完全与函数returnFun一致
    return ::returnFun
    }
    //返回lambda
    return {a -> a + 10}
    }

/**

  • 作为高阶函数的返回函数
    */
    fun returnFun(a:Int):Int{
    return a * 100
    }
//使用高阶函数
val res = highFunction2("A")
println(res(20)) //打印2000
val res2 = highFunction2("B")
println(res2(20)) //打印30

扩展函数

fun main() {open class Shapeclass Rectangle: Shape()fun Shape.getName() = "Shape"fun Rectangle.getName() = "Rectangle"fun printClassName(s: Shape) {println(s.getName())}    printClassName(Rectangle())

上面函数的最终返回结果是打印"Shape",因为虽然printClassName的函数的传入参数是Rectangle()函数,但是最终会调用Shape类的getName()函数,这是因为最终返回的类型取决于printClassName函数传入参数s的类型

成员函数与扩展函数

如果一个类定义有一个成员函数与一个扩展函数,而这两个函数又有相同的接收者类型、 相同的名字,并且都适用给定的参数,这种情况总是取成员函数
示例

fun main() {class Example {fun printFunctionType() { println("Class method") }}fun Example.printFunctionType() { println("Extension function") }Example().printFunctionType()
}

这里最后会输出:“Class method”,因为是以类的成员函数为准的,优先级为先成员函数
如果是扩展类型的重载,那么以传入参数为准
由于静态调用扩展方法是在编译时执行,因此,如果父类和子类都扩展了同名的一个扩展方法,引用类型均为父类的情况下,会调用父类的扩展方法
示例

fun main() {class Example {fun printFunctionType() { println("Class method") }}fun Example.printFunctionType(i: Int) { println("Extension function") }Example().printFunctionType(1)
}

最后输出结果为:Extension function

top-level函数

不依赖于任何类的静态函数,经Kotlin编译成Java文件后,成为:<静态函数所在的文件名> + "Kt"的Java类的静态成员函数。如果原kotlin文件的文件名首字母为小写时,转换成大写。
示例

/** joinsample.kt */
package com.example.kotlinimport java.lang.StringBuilderfun <T> joinToString(collection: Collection<T>,separator: String = ", ",prefix: String = "",postfix: String = ""
): String {val result = StringBuilder(prefix)for ((index, element) in collection.withIndex()) {if (index > 0) {result.append(separator)}result.append(element)}result.append(postfix)return result.toString()
}
import com.example.kotlin.JoinsampleKt;
import java.util.Arrays;
import java.util.List;public class JavaSample {public static void main(String[] args) {List<String> list = Arrays.asList("hello", "world");JoinsampleKt.joinToString(list, ", ", "", "");}
}

扩展属性

由于扩展没有实际的将成员插入类中,因此对扩展属性来说幕后字段是无效的。这就是为什么扩展属性不能有初始化器。他们的行为只能由显式提供的 getters/setters 定义。

扩展声明为成员

就是说有两个类,可以在其中一个类中为另一个类声明一个扩展函数,被声明的扩展函数,此时是当前类的成员函数

示例

class Host(val hostname: String) {fun printHostname() { print(hostname) }
}class Connection(val host: Host, val port: Int) {fun printPort() { print(port) }// 这里可以为Host类定义扩展函数,是因为类Connection的主构造函数中将Host类传入进来fun Host.printConnectionString() {printHostname()   // 调用 Host.printHostname()print(":")printPort()   // 调用 Connection.printPort()}fun connect() {/*……*/host.printConnectionString()   // 调用扩展函数}
}fun main() {// 这里直接使用类Connection的主构造函数传入Host类然后调用Host的主构造函数,然后调用Host类的printHostname()函数// 被定义的扩展函数必须在定义该扩展函数的类中使用// 意思就是说Host的printConnectionString()函数必须在类Connection中使用//  Connection(Host("kotl.in"),443).printConnectionString()Connection(Host("kotl.in"), 443).connect()//Host("kotl.in").printConnectionString(443)  // 错误,该扩展函数在 Connection 外不可用
}
class Connection {// 这里给Host类定义一个扩展函数// 在这个扩展函数中调用toString()// 因为在kotlin中所有的类都继承自Any类,而toString方法是属于Any类的// 如果想调用Connection类的toString()方法需要向下面那种写法// this@Connection.toString()fun Host.getConnectionString() {toString()         // 调用 Host.toString()this@Connection.toString()  // 调用 Connection.toString()}
}

泛型中的in和out

这两个泛型的定义为逆变与携变
示例

// 逆变
interface Consumer<in T> {fun consume(item: T)
}

简单来说就是在接口中in标记的泛型类型T,要作为函数consume的入参类型

// 携变
interface Production<out T> {fun produce(): T
}

简单来说就是接口泛型中out标记的T要做为函数produce返回的类型

相关文章:

kotlin高阶函数

kotlin高阶函数 函数式API:一个函数的入参数为Lambda表达式的函数就是函数式api 例子: public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {return filterTo(ArrayList<T>(), predicate) }上面这段函数: 首先这个函…...

kotlin list集合树

kotlin list集合树 记录一下 data class AreaSchemaManageDto(var id: Long? null,var pid: Long? null,var label: String? null,var children: MutableList<AreaSchemaManageDto>? null ) : Serializable { }逻辑 fun getAll(): List<AreaSchemaManageDto&g…...

基于Autoencoder自编码的64QAM星座图整形调制解调通信系统性能matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1星座图整形 4.2自编码器 4.3基于Autoencoder的星座图整形调制解调模型 4.4 实现过程 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 matlab2022a 3.部分核心程序 .…...

【Spring】Spring 总览

一、简单介绍一下 Spring Spring是一个全面的、企业应用开发的一站式解决方案&#xff0c;贯穿表现层、业务层、持久层&#xff0c;可以轻松和其他框架整合&#xff0c;具有轻量级、控制反转、面向切面、容器等特征。 轻量级 &#xff1a; 空间开销和时间开销都很轻量 控制反…...

微软、OpenAI用上“数据永动机” 合成数据是晨曦还是暮光?

微软、OpenAI、Cohere等公司已经开始测试使用合成数据来训练AI模型。Cohere首席执行官Aiden Gomez表示&#xff0c;合成数据可以适用于很多训练场景&#xff0c;只是目前尚未全面推广。 已有的&#xff08;通用&#xff09;数据资源似乎接近效能极限&#xff0c;开发人员认为&a…...

简单认识Redis 数据库的高可用

文章目录 一、Redis 高可用&#xff1a;1.简介&#xff1a;2、在Redis中实现高可用的技术 二、Redis持久化&#xff1a;1.持久化的功能&#xff1a;2.Redis 提供两种方式进行持久化&#xff1a; 三、RDB 持久化&#xff1a;1.简介&#xff1a;2.触发条件&#xff1a;4.启动时加…...

超级实用!,掌握这9个鲜为人知的CSS属性

微信搜索 【大迁世界】, 我会第一时间和你分享前端行业趋势&#xff0c;学习途径等等。 本文 GitHub https://github.com/qq449245884/xiaozhi 已收录&#xff0c;有一线大厂面试完整考点、资料以及我的系列文章。 快来免费体验ChatGpt plus版本的&#xff0c;我们出的钱 体验地…...

深圳国际新能源及智能网联汽车全产业博览会今年10月举办

7月25日&#xff0c;深圳市工业和信息化局与励展博览集团共同在深圳举办Automotive World China 2023深圳国际新能源及智能网联汽车全产业博览会&#xff08;简称“AWC 2023”&#xff09;全球推介启动大会&#xff0c;该博览会将于2023年10月11日-13日在深圳国际会展中心盛大举…...

【具有非线性反馈的LTI系统识别】针对反馈非线性的LTI系统,提供非线性辨识方案(SimulinkMatlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f308;4 Matlab代码、Simulink仿真实现 &#x1f4a5;1 概述 本文为具有反馈非线性的LTI系统提供了一种非线性识别方案&#xff0c;这取决于输入和LTI系统输出。对于MEMS来说尤其如此&#…...

Stable diffusion 和 Midjourney 怎么选?

通过这段时间的摸索&#xff0c;我将和你探讨&#xff0c;对普通人来说&#xff0c;Stable diffusion 和 Midjourney 怎么选&#xff1f;最重要的是&#xff0c;学好影视后期制作对 AI 绘画创作有哪些帮助&#xff1f;反过来&#xff0c;AI 绘画对影视后期又有哪些帮助&#xf…...

c++网络编程

网络编程模型 c/s 模型&#xff1a;客户端服务器模型b/s 模型&#xff1a;浏览器服务器模型1.tcp网络流程 服务器流程&#xff1a; 1.创建套接字2.完善服务器网络信息结构体3.绑定服务器网络信息结构体4.让服务器处于监听状态5.accept阻塞等待客户端连接信号6.收发数据7.关闭套…...

【沁恒蓝牙mesh】数据收发接口与应用层模型传递

本文主要描述了沁恒蓝牙mesh SDK的蓝牙数据收发接口&#xff0c;以及应用层的回调函数解析以及模型传递 这里写目录标题 1. 数据收发接口1.1【发送数据】1.2 【数据接收】 2. 应用层模型分析 1. 数据收发接口 1.1【发送数据】 /*&#xff08;1&#xff09;接口1 */ /*接口一&…...

Java类关系之代理(代理模式)

在Java中&#xff0c;如果一个类需要使用另一个类的方法&#xff0c;我们可以使用继承的方式实现&#xff0c;那么问题来了&#xff0c;如果这个类恰恰在逻辑关系上不能使用继承怎么办呢&#xff1f;比如说&#xff0c;飞机和控制台这两个类&#xff0c;控制台的方法有上下左右…...

java: 无法访问redis.clients.jedis.JedisPoolConfig

问题描述: 在编译java springboot程序的时候报错 java: 无法访问redis.clients.jedis.JedisPoolConfig 找不到redis.clients.jedis.JedisPoolConfig的类文件 问题分析 该问题是由于找不到JedisPoolConfig包导致的,很可能是没有添加相关的依赖 问题解决 在pom文件中添加依赖项…...

基于java中学教务管理系统设计与实现

摘要 随着现代技术的不断发展&#xff0c;计算机已经深度的应用到了当下的各个行业之中&#xff0c;教育行业也不例外。计算机对教育行业中的教务管理等内容的帮助&#xff0c;使得教职工从传统的手工办公像计算机辅助阶段迈进&#xff0c;并且实现了非常好的发展。现在的学校在…...

vscode设置java -Xmx最大堆内存

如果在vscode中直接运行java程序&#xff0c;想要改下每次运行的最大堆内存&#xff0c;按照如下修改 一、vscode安装java插件 当然前提是vscode在应用管理中已经安装了java语言的插件&#xff0c;Debugger for Java,如下图所示 二、CommandShiftP打开配置搜索框 三、搜索…...

组件开发系列--Apache Commons Chain

一、前言 Commons-chain是apache commons中的一个子项目,主要被使用在"责任链"的场景中,struts中action的调用过程,就是使用了"chain"框架做支撑.如果你的项目中,也有基于此种场景的需求,可以考虑使用它. 在责任链模式里&#xff0c;很多对象由每一个对象对…...

60 # http 的基本概念

什么是 HTTP&#xff1f; 通常的网络是在 TCP/IP 协议族的基础上来运作的&#xff0c;HTTP 是一个子集。http 基于 tcp 的协议&#xff0c;在 tcp 的基础上增加了一些规范&#xff0c;就是 header&#xff0c;学习 http 就是学习每个 header 它有什么作用。 TCP/IP 协议族 协…...

云计算迎来中场战役,MaaS或将成为弯道超车“新赛点”

科技云报道原创。 没有人能预见未来&#xff0c;但我们可以因循常识&#xff0c;去捕捉技术创新演进的节奏韵脚。 2023年最火的风口莫过于大模型。 2022年底&#xff0c;由美国初创企业OpenAI开发的聊天应用ChatGPT引爆市场&#xff0c;生成式AI成为科技市场热点&#xff0c…...

最新基于Citespace、vosviewer、R语言的文献计量学可视化分析技术及全流程文献可视化SCI论文高效写作方法

文献计量学是指用数学和统计学的方法&#xff0c;定量地分析一切知识载体的交叉科学。它是集数学、统计学、文献学为一体&#xff0c;注重量化的综合性知识体系。特别是&#xff0c;信息可视化技术手段和方法的运用&#xff0c;可直观的展示主题的研究发展历程、研究现状、研究…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

边缘计算医疗风险自查APP开发方案

核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

vue3 daterange正则踩坑

<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...

实战设计模式之模板方法模式

概述 模板方法模式定义了一个操作中的算法骨架&#xff0c;并将某些步骤延迟到子类中实现。模板方法使得子类可以在不改变算法结构的前提下&#xff0c;重新定义算法中的某些步骤。简单来说&#xff0c;就是在一个方法中定义了要执行的步骤顺序或算法框架&#xff0c;但允许子类…...

【若依】框架项目部署笔记

参考【SpringBoot】【Vue】项目部署_no main manifest attribute, in springboot-0.0.1-sn-CSDN博客 多一个redis安装 准备工作&#xff1a; 压缩包下载&#xff1a;http://download.redis.io/releases 1. 上传压缩包&#xff0c;并进入压缩包所在目录&#xff0c;解压到目标…...