zoukankan      html  css  js  c++  java
  • Kotlin学习与实践 (九)带接收者的lambda及Java的函数式接口

    带接收者的lambda

    * 在lambda 函数体内可以调用一个不同对象的方法,而且无须借助任何额外限定符;这种能力再Java中是找不到的。
    * 这样的lambda叫做“带接收者的lambda”

    先举个普通函数作为反例:
    fun alphabet(): String {
        val result = StringBuilder()
        for (letter in 'A'..'Z') {
            result.append(letter)
        }
        result.append("
    Now ,I know the alphabet")
        return result.toString()
    }
    

      在上面的例子中可以看到函数中对 result 对象反复的调用,如果反复调用的多了就会变得很糟,Kotlin 带接受者的lambda就解决了这个问题。

    首先看wtih函数:

    *  with 语法 是一个接收两个参数的函数:严格的写应该是 with(aa,{...lambda...}), 利用把lambda 作为最后一个参数可以放到括号外面的约定可以提高可读性  with(xx){...lambda...}
    * with函数把第一个参数 转化成 作为第二个参数的lambda 的接收者,可以显式地通过this 引用来访问这个接收者,也可以省略this 引用直接访问
    fun alphabetWith(): String {
        val result = StringBuilder()
        return with(result) {
            //指定接收者的值,然后就可以在lambda中使用
            for (letter in 'A'..'Z') {
                this.append(letter) //通过this显示的来调用接收者
            }
            append("
    Now ,I know the alphabet")//也可以省掉this 来调用接收者
            result.append("hahaha")
            this.toString() //从lambda中返回
        }
    }
    * 可以使用表达式函数体语法继续简化函数。
    fun alpabetWithF() = with(StringBuilder()) {
        for (letter in 'A'..'Z') {
            this.append(letter) //通过this显示的来调用接收者
        }
        append("
    Now ,I know the alphabet")//也可以省掉this 来调用接收者
        append("hahaha")
        toString() //从lambda中返回
    }
    
    
    
    * with返回值是执行lambda代码的结果,改结果就是lambda中的最后一个表达式的值。
    * 如果你想返回的是接收者对象(传入lambda的对象)而不是lambda执行的结果时候,apply函数就排上用场了。

    * apply被声明成一个扩展函数。它的接收者变成了作为实参的lambda的接收者。
    * 执行apply的结果是StringBuilder,所以接下来你可以调用toString把它转化成String。
    fun alpabetApply() = StringBuilder().apply {
        for (letter in 'A'..'Z') {
            this.append(letter) //通过this显示的来调用接收者
        }
        append("
    Now ,I know the alphabet")//也可以省掉this 来调用接收者
        append("hahaha")
    }.toString()
    * Kotlin中可以再任意对象上使用apply,不需要任何特别的支持
    * apply 允许你使用紧凑的表达式函数体的风格
    * lambda执行之后,apply返回已经初始化过的接收者实例
    
    
    fun createViewWithCustomAttribites(context:Context)= TextView(context).apply{
    text = "Simple Text"
    testSize = 20
    setPadding(20,15,1,0)
    }
    
    
    

      以上是Kotlin中最典型最基本的带接受者的lambda函数,除了with apply之外还有其他的使用起来很赞的带接受者的函数....

    使用Java的函数式接口

    * 在Kotlin中可以传递一个lambda 代替传统的Java中的匿名类做实参
    * 使用lambda代替Java匿名类的方式可以工作的原因是 ActionListener 接口中只有一个抽象方法。(Runnable、Callable)
    * 这种接口被称为函数式接口,或者SAM接口,SAM代表单抽象方法。
    * Kotlin 允许你再调用接收函数式接口作为参数的方式时使用lambda,来保证代码的整洁。
    
    
    fun lambdaInnerClass() {
    //    val btn = Button()
    //    btn.setOnclickListener{v-> println("")}
    
        val btn = Button()
        btn.addActionListener { e -> println("hahaha") }
    }
    
    
    

    下面来一个演示的例子,首先放出Java定义的函数:

    public class JavaCallTest {
      
        public void postponeComputation(int delay, Runnable computation) {
            Thread thread = new Thread(computation);
            try {
                thread.join(delay);
                thread.start();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
    }
    * 在Koltin中使用lambda代替匿名类参数,编译器会把最后打lambda 自动编译转换成一个Runnable实例传递给方法
    
    
    val javaTest = JavaCallTest()
    fun testLambdaCallJava() {
        javaTest.postponeComputation(100) {
            println(42)
        }
    
         // 如下通过显示创建匿名对象也能达到效果
        javaTest.postponeComputation(1000, object : Runnable {
            override fun run() {
                println("452")
            }
    
        })
    }
    
    
    
    * 这里有一点不一样,当你显式地声明对象时,每次调用都会创建一个新的对象。
    * 使用lambda的情况不同:如果lambda没有访问任何来自定义它的函数的变量,响应的匿名类对象可以在多次调用之间重用。
    
    
    val runnable = Runnable { println(42) }
    fun reUsing() {
        javaTest.postponeComputation(1000, runnable)
    }
    
    
    
    * 上面的runnable 使用lambda对应生成的对象就会多次复用 因为没有没有引用函数中定义的变量
    * 如果lambda从包围它的作用域中捕捉了变量,每次调用就不能再重复利用同一个实例了,这时每次就会创建一个新的对象,其中存储着被捕获的变量的值
    * 如下:
    fun handleComputation(id: String) {
        javaTest.postponeComputation(1000) {
            println(id)
        }
    }
    
    
    
    SAM接口还有一些别的特性,暂时就不列举出来了...
     
  • 相关阅读:
    C# 如何定义让PropertyGrid控件显示[...]按钮,并且点击后以下拉框形式显示自定义控件编辑属性值
    “Word自动更改后的内容保存到通用文档模板上。是否加载该模板?“的解决办法
    Web服务器之iis,apache,tomcat三者之间的比较
    [转]C#如何把文件夹压缩打包然后下载
    [转]C#压缩打包文件
    C#——Marshal.StructureToPtr方法简介
    [Android Pro] 内容提供者ContentProvider的基本使用
    [Linux] awk命令详解
    [Linux] AWK命令详解(大全)
    [Android UI] ProgressBar自定义
  • 原文地址:https://www.cnblogs.com/mauiie/p/SAM_lambda.html
Copyright © 2011-2022 走看看