学习笔记-Kotlin(2)

目录

1.函数内联

2.函数引用

3.函数类型作为返回类型

4.闭包

5.Null

(1)安全调用操作符

(2)非空断言操作符

(3)使用if判断空值

(4)使用空合并操作符

6.异常

1.函数内联

       有关内联的引出,有些材料上说的是:在JVM上,你定义的lambda会以对象实例的形式存在,JVM会为所有同lambda打交道的变量分配内存,这就产生了内存开销,更糟的是,lambda的内存开销会带来严重的性能问题。幸运的是,kotlin有一种优化机制叫内联,有了内联,JVM就不需要使用lambda对象实例了,因而避免了变量内存分配。哪里需要使用lambda,编译器就会将函数体复制粘贴到哪里。
       值得注意的是,使用lambda的递归函数无法内联因为会导致赋值粘贴无限循环,编译会警告。
       内联函数的关键字是inline。例如上次的学习笔记-kotlin(1)中的高阶函数代码咱们来看看它的字节码。操作步骤show kotlin -> Decompile 转换成java咱们更方便看。

fun main(){
    val meilidepaomo:(String, Int) -> String = {goodsName, hour ->
        val currentYear : Int = 2007
        "${currentYear}年, 双11${goodsName}的促销事件剩余${hour}小时"
    }
    showOnBoard("安慕希", meilidepaomo)
}

private fun showOnBoard(goodsName:String, showdowns:(String, Int) -> String) {
    val hour : Int = 6
    println(showdowns(goodsName, hour))
}
public final void main() {
    Function2 meilidepaomo = (Function2)null.INSTANCE;
    this.showOnBoard("安慕希", meilidepaomo);
}

private final void showOnBoard(String goodsName, Function2 showdowns) {
    int hour = 6;
    Object var4 = showdowns.invoke(goodsName, Integer.valueOf(hour));
    boolean var5 = false;
    System.out.println(var4);
}

上边没有使用内联关键字的时候的字节码
下边使用了内联关键字的字节码

fun main(){
    val meilidepaomo:(String, Int) -> String = {goodsName, hour ->
        val currentYear : Int = 2007
        "${currentYear}年, 双11${goodsName}的促销事件剩余${hour}小时"
    }
    showOnBoard("安慕希", meilidepaomo)
}

private inline fun showOnBoard(goodsName:String, showdowns:(String, Int) -> String) {
    val hour : Int = 6
    println(showdowns(goodsName, hour))
}
public final void main() {
   Function2 meilidepaomo = (Function2)null.INSTANCE;
   String goodsName$iv = "安慕希";
   int $i$f$showOnBoard = false;
   int hour$iv = 6;
   Object var6 = meilidepaomo.invoke(goodsName$iv, Integer.valueOf(hour$iv));
   boolean var7 = false;
   System.out.println(var6);
}

private final void showOnBoard(String goodsName, Function2 showdowns) {
   int $i$f$showOnBoard = 0;
   int hour = 6;
   Object var5 = showdowns.invoke(goodsName, Integer.valueOf(hour));
   boolean var6 = false;
   System.out.println(var5);
}

       我们能看出来showOnBoard()函数在加了inline内联关键字后的字节码,把其函数体内的代码赋值粘贴到了main()

2.函数引用

       函数引用方式::函数名
     
示例:将上边的代码改成具名函数后

fun main(){
    showOnBoard("安慕希", ::meilidepaomo)
}

private fun showOnBoard(goodsName:String, showdowns:(String, Int) -> String) {
    val hour : Int = 6
    println(showdowns(goodsName, hour))
}

private fun meilidepaomo(goodsName:String, hour:Int):String {
    val currentYear : Int = 2007
    return "${currentYear}年, 双11${goodsName}的促销事件剩余${hour}小时"
}

3.函数类型作为返回类型

       函数类型也是返回类型,可以定义一个返回函数的函数。有点绕嘴,哈哈哈。

fun main(){
    val meilidepaomo = showOnBoard();
    println(meilidepaomo("蜡笔小新"))
}

private fun showOnBoard() : (String) -> String {
    val currentYear : Int = 2007;
    val hour : Int = 5;
    return {goodsName:String ->
        "${currentYear}年,双11${goodsName}促销倒计时,剩余${hour}小时"
    }
}

       其中showOnBoard()函数的返回类型是(String)->String的一个函数(一个String的参数,返回值为String),使用meilidepaomo的时候传入一个String参数即可
       运行结果:2007年,双11蜡笔小新促销倒计时,剩余5小时

4.闭包

       闭包的概念:匿名函数能修改并引用定义在自己的作用域之外的变量,匿名函数引用着定义自身的函数里的变量,kotlin中的lambda就是闭包。换成通俗的讲法就是,function2在funtion1中,function2使用了funtion1中的变量,这个时候我们就称为闭包。
       闭包存在的意义是什么呢?我找到的资料是,kotlin学习脚本语言,脚本语言没有Package的概念,当一个变量在文件A中声明了,在B中用相同的名字声明,就编译警告了。闭包能够保证其作用域。

5.Null

       kotlin区分可空类型和非可空类型。空值异常kotlin会在编译时就警告,而不是等到运行之后再崩溃。除非你接手处理。处理的方式有:

(1)安全调用操作符

       操作符:

val i:Int? = null

       这样我们的Int就是可空类型的了,编辑器再看到安全调用符,如果为空值,就会跳过函数调用,而不是让空值继续执行函数,如:

fun main(){
    val str : String? = getStr()?.plus("222")
    println(str)
}
private fun getStr():String? {
    return "LOVE";
}

运行结果:LOVE222

fun main(){
    val str : String? = getStr()?.plus("222")
    println(str)
}
private fun getStr():String? {
    return null;
}

运行结果:null
       代码不难,getStr()函数返回一个可空的String,?.plus表示不为空的话执行plus方法。第一段代码运行结果LOVE222表示走进了plus()函数,第二段代码运行结果null,表示跳过了函数调用。这样咱们就可以理解之前的一些概念了。

(2)非空断言操作符

       操作符:!!

val str : String? = getStr()!!.plus("222")

       咱们不管是否为空就是要走plus,就可以这样使用,但这样容易空指针异常

(3)使用if判断空值

       这个很好理解了,跟java差不多

if(str == null) {.......}

(4)使用空合并操作符

       操作符:?:

fun main(){
    val str : String? = getStr()?.plus("222")?:"111111"
    println(str)
}
private fun getStr():String? {
    return null;
}

 运行结果:111111
       
如果为空的话,就执行后面的东西。从运行结果上来看,也符合这样的一个逻辑。个人感觉起来更像是3原运算符似的boolean ? 结果1 : 结果2。

6.异常

       抛出异常和java相同

try{
    .....
} catch(e:Exception){
    println(e)
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值