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是一个全面的、企业应用开发的一站式解决方案,贯穿表现层、业务层、持久层,可以轻松和其他框架整合,具有轻量级、控制反转、面向切面、容器等特征。 轻量级 : 空间开销和时间开销都很轻量 控制反…...

微软、OpenAI用上“数据永动机” 合成数据是晨曦还是暮光?
微软、OpenAI、Cohere等公司已经开始测试使用合成数据来训练AI模型。Cohere首席执行官Aiden Gomez表示,合成数据可以适用于很多训练场景,只是目前尚未全面推广。 已有的(通用)数据资源似乎接近效能极限,开发人员认为&a…...

简单认识Redis 数据库的高可用
文章目录 一、Redis 高可用:1.简介:2、在Redis中实现高可用的技术 二、Redis持久化:1.持久化的功能:2.Redis 提供两种方式进行持久化: 三、RDB 持久化:1.简介:2.触发条件:4.启动时加…...
超级实用!,掌握这9个鲜为人知的CSS属性
微信搜索 【大迁世界】, 我会第一时间和你分享前端行业趋势,学习途径等等。 本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试完整考点、资料以及我的系列文章。 快来免费体验ChatGpt plus版本的,我们出的钱 体验地…...

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

【具有非线性反馈的LTI系统识别】针对反馈非线性的LTI系统,提供非线性辨识方案(SimulinkMatlab代码实现)
目录 💥1 概述 📚2 运行结果 🎉3 参考文献 🌈4 Matlab代码、Simulink仿真实现 💥1 概述 本文为具有反馈非线性的LTI系统提供了一种非线性识别方案,这取决于输入和LTI系统输出。对于MEMS来说尤其如此&#…...

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

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

【沁恒蓝牙mesh】数据收发接口与应用层模型传递
本文主要描述了沁恒蓝牙mesh SDK的蓝牙数据收发接口,以及应用层的回调函数解析以及模型传递 这里写目录标题 1. 数据收发接口1.1【发送数据】1.2 【数据接收】 2. 应用层模型分析 1. 数据收发接口 1.1【发送数据】 /*(1)接口1 */ /*接口一&…...
Java类关系之代理(代理模式)
在Java中,如果一个类需要使用另一个类的方法,我们可以使用继承的方式实现,那么问题来了,如果这个类恰恰在逻辑关系上不能使用继承怎么办呢?比如说,飞机和控制台这两个类,控制台的方法有上下左右…...
java: 无法访问redis.clients.jedis.JedisPoolConfig
问题描述: 在编译java springboot程序的时候报错 java: 无法访问redis.clients.jedis.JedisPoolConfig 找不到redis.clients.jedis.JedisPoolConfig的类文件 问题分析 该问题是由于找不到JedisPoolConfig包导致的,很可能是没有添加相关的依赖 问题解决 在pom文件中添加依赖项…...
基于java中学教务管理系统设计与实现
摘要 随着现代技术的不断发展,计算机已经深度的应用到了当下的各个行业之中,教育行业也不例外。计算机对教育行业中的教务管理等内容的帮助,使得教职工从传统的手工办公像计算机辅助阶段迈进,并且实现了非常好的发展。现在的学校在…...

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

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

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

云计算迎来中场战役,MaaS或将成为弯道超车“新赛点”
科技云报道原创。 没有人能预见未来,但我们可以因循常识,去捕捉技术创新演进的节奏韵脚。 2023年最火的风口莫过于大模型。 2022年底,由美国初创企业OpenAI开发的聊天应用ChatGPT引爆市场,生成式AI成为科技市场热点,…...

最新基于Citespace、vosviewer、R语言的文献计量学可视化分析技术及全流程文献可视化SCI论文高效写作方法
文献计量学是指用数学和统计学的方法,定量地分析一切知识载体的交叉科学。它是集数学、统计学、文献学为一体,注重量化的综合性知识体系。特别是,信息可视化技术手段和方法的运用,可直观的展示主题的研究发展历程、研究现状、研究…...
变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析
一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...

mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...

前端开发者常用网站
Can I use网站:一个查询网页技术兼容性的网站 一个查询网页技术兼容性的网站Can I use:Can I use... Support tables for HTML5, CSS3, etc (查询浏览器对HTML5的支持情况) 权威网站:MDN JavaScript权威网站:JavaScript | MDN...
书籍“之“字形打印矩阵(8)0609
题目 给定一个矩阵matrix,按照"之"字形的方式打印这个矩阵,例如: 1 2 3 4 5 6 7 8 9 10 11 12 ”之“字形打印的结果为:1,…...

针对药品仓库的效期管理问题,如何利用WMS系统“破局”
案例: 某医药分销企业,主要经营各类药品的批发与零售。由于药品的特殊性,效期管理至关重要,但该企业一直面临效期问题的困扰。在未使用WMS系统之前,其药品入库、存储、出库等环节的效期管理主要依赖人工记录与检查。库…...

HTTPS证书一年多少钱?
HTTPS证书作为保障网站数据传输安全的重要工具,成为众多网站运营者的必备选择。然而,面对市场上种类繁多的HTTPS证书,其一年费用究竟是多少,又受哪些因素影响呢? 首先,HTTPS证书通常在PinTrust这样的专业平…...

【Qt】控件 QWidget
控件 QWidget 一. 控件概述二. QWidget 的核心属性可用状态:enabled几何:geometrywindows frame 窗口框架的影响 窗口标题:windowTitle窗口图标:windowIconqrc 机制 窗口不透明度:windowOpacity光标:cursor…...

Spring是如何实现无代理对象的循环依赖
无代理对象的循环依赖 什么是循环依赖解决方案实现方式测试验证 引入代理对象的影响创建代理对象问题分析 源码见:mini-spring 什么是循环依赖 循环依赖是指在对象创建过程中,两个或多个对象相互依赖,导致创建过程陷入死循环。以下通过一个简…...