Kotlin学习与实践 (九)带接收者的lambda及Java的函数式接口

带接收者的lambda

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

先举个普通函数作为反例:
fun alphabet(): String {
    val result = StringBuilder()
    for (letter in ‘A‘..‘Z‘) {
        result.append(letter)
    }
    result.append("\nNow ,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("\nNow ,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("\nNow ,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("\nNow ,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接口还有一些别的特性,暂时就不列举出来了...
 

原文地址:https://www.cnblogs.com/mauiie/p/SAM_lambda.html

时间: 2024-08-26 20:28:02

Kotlin学习与实践 (九)带接收者的lambda及Java的函数式接口的相关文章

Kotlin学习与实践 (四)类、接口

1.类的继承结构 接口 * Kotlin的类和接口与Java的有些地方不一样:* Kotlin的声明默认是public final的.* Kotlin嵌套的类默认不是内部类:它没有包含对外部类的隐式引用 等* Kotlin也一样是使用interface来声明接口 * 如下: 声明一个简单的接口 interface Clickable { fun click() fun longPress() = println("longPress") //接口中的抽象方法也可以有默认的实现,有了默认

Kotlin学习与实践 (三)fun 函数

通过例子来学习如何高效的在Kotlin中定义使用函数. 1.命名参数.默认参数.顶层函数.扩展函数 * 展示几种创建集合类的方法和扩展的简单操作集合类的方法 fun createCollection() { val set = hashSetOf(1, 12, 26) println("hashSetOf -- > ${set.javaClass}") val list = arrayListOf(12, 24, 66) println("arrayListOf --

Kotlin学习与实践 (十)Kotlin的可控性

可空类型 * 类型就是数据的分类.决定了该类型可能的值,以及在该类型值上可以完成的操作. * 与Java不同,Kotlin对可空类型的显示的支持.可空类型是Kotlin类型系统中帮助避免NullPointException错误的特性.* 这是一种指出你的程序中那些变量和属性允许为null的方式. * 可空类型和非可空类型的对象在运行时没有什么区别,可空类型并不是非空类型的包装.所有检查都是在编译时期,所以Kotlin的可空类型并不会在运行时带来额外的开销.先来看看Java中的空指针是怎么造成的

基于Spark的机器学习实践 (九) - 聚类算法

0 相关源码 1 k-平均算法(k-means clustering)概述 1.1 回顾无监督学习 ◆ 分类.回归都属于监督学习 ◆ 无监督学习是不需要用户去指定标签的 ◆ 而我们看到的分类.回归算法都需要用户输入的训练数据集中给定一个个明确的y值 1.2 k-平均算法与无监督学习 ◆ k-平均算法是无监督学习的一种 ◆ 它不需要人为指定一个因变量,即标签y ,而是由程序自己发现,给出类别y ◆ 除此之外,无监督算法还有PCA,GMM等 源于信号处理中的一种向量量化方法,现在则更多地作为一种聚类

GDI+学习笔记(九)带插件的排序算法演示器(MFC中的GDI+实例)

带插件的排序算法演示器 本节将通过一个实例来说明GDI+在MFC中的应用.这个算法演示器其实是本人算法系列的一个开端,由于csdn没有树状的目录结构,咱也只好使用链表了不是?好了,废话不多说,开始今天的文章. (一)功能说明 我们初步制定功能如下: (1). 能够通过柱状图,自动展示排序算法的交换比较过程 (2). 能够使用插件的形式进行开发.即,当新完成一个算法后,只需要完成一个插件文件(我们这里使用动态库dll),由主程序加载插件,即可进行执行,而不再需要重新编译主程序. (3). 保证主程

java泛型学习和实践(4)

引言 前三节讲述了泛型常见声明及使用,泛型既可以在类上进行声明,也可以在单个方法上进行声明,并分别对这两种情况进行了总结.下面来学习下泛型扩展知识. 延用前面的Runnable接口.Buick类.Ford类.Driver类,新增加一个汽车容器类CarContainer 第一版 代码如下: public interface Runnable { public void run(); } public class Buick implements Runnable { @Override publi

C++语言学习(十九)——C++类型识别

C++语言学习(十九)--C++类型识别 一.C++类型识别简介 1.C++类型识别简介 C++是静态类型语言,其数据类型是在编译期就确定的,不能在运行时更改.C++语言中,静态类型是对象自身的类型,动态类型是指针(引用)所指向对象的实际类型.RTTI(Run-Time Type Information)即运行时类型识别,C++通过RTTI实现对多态的支持.为了支持RTTI,C++提供了一个type_info类和typeid与dynamic_cast两个关键字. 2.type_info结构体 t

《解析深度学习 语音识别实践》高清中文版PDF下载

<解析深度学习 语音识别实践>高清中文版PDF下载高清中文版PDF,全书321页带目录 下载链接:https://pan.baidu.com/s/1Ly4sdpNpcU_AwnwEVdBKLA备用链接:https://u1593575.ctfile.com/fs/1593575-330744495 本书首次专门讲述了如何将深度学习方法,特别是深度神经网络(DNN)技术应用于语音识别(ASR)领域.在过去的几年中,深度神经网络技术在语音识别领域的应用取得了前所未有的成功.这使得本书成为在深度神经

k8s实践(九):Helm and Kubeapps UI

环境说明: 主机名 操作系统版本 ip docker version kubelet version helm version 配置 备注 master Centos 7.6.1810 172.27.9.131 Docker 18.09.6 V1.14.2 v2.14.3 2C2G master主机 node01 Centos 7.6.1810 172.27.9.135 Docker 18.09.6 V1.14.2 v2.14.3 2C2G node节点 node02 Centos 7.6.18