kotlin lambda简介

发布时间 2023-11-01 00:38:38作者: LCAC

一、作为函数的代码块

java的接口

    public interface OnClickListener {
        void onClick(String v);
    }

 

1、使用java的方式进行创建匿名内部类的方式进行继承

        OnClickListener listener = new OnClickListener() {
            @Override
            public void onClick(String v) { // 这里实现OnClickListener的函数
                System.out.println("new OnClickListener():" + v);
            }
        };

        listener.onClick("kk"); //输出:new OnClickListener():kk

 

2、使用java的方式进行创建lambda

        OnClickListener listenerLambda = v -> {
            System.out.println("lambda:" + v);
        };
        listenerLambda.onClick("qqq"); // 输出:lambda:qqq

java在使用lambda在继承方面看似也不错,很简洁

 

kotlin的接口

interface OnClickListener1 {
    fun onClick(v: String)
}

fun testClick2(clickListener1: OnClickListener1) {
    clickListener1.onClick("kkqqq")
}

 

3、使用kotlin匿名内部类的方式

    testClick2(object: OnClickListener1 {
        override fun onClick(v: String) {
            println("object: OnClickListener1:${v}")
        }
    })
// 输出:object: OnClickListener1:kkqqq

看着跟java的匿名内部类差不多

 

4、使用kotlin的方式创建lambda

这边在使用kotlin的lambda调用上述的testClick2,按照正常的想法应该是能够正确推理出:OnClickListener1 接口

testClick2 { println("lambda interface:$it")} // 这样子调用老是提示:Type mismatch.

这是为啥呢?

这里先改变一下testClick2的参数为上述java的接口

fun testClick1(clickListener: OnClickListener) { // OnClickListener是上述的java的接口
    clickListener.onClick("kkqqq")
}

testClick1 { println("lambda interface:$it")} // 能正确输出:lambda interface:kkqqq

为啥使用java的接口可以但是kotlin的接口就不行呢?

官方的解释是 Kotlin 本身已经有了函数类型和高阶函数等支持,所以不需要再去转换。如果你想使用类似的需要用 lambda 做参数的操作,应该自己去定义需要指定函数类型的高阶函数。

 

二、SAM转换的概念

SAM转换的英文全拼是:Single Abstract Method Conversions。就是对于只有单个非默认抽象方法接口的转换 ,对于符合这个条件的接口在 Kotlin 中可以直接用 Lambda 来表示 (前提是 Lambda 的所表示函数类型能够跟接口中的方法相匹配)

例子:

上述的testClick1对应的接口是OnClickListener,对testClick1的传入参数是lambda表达式,该lambda表达式的类型是:(String) -> Unit , 正好跟OnClickListener接口的单一方法接口类型一样:void onClick(String v) ;所以testClick1的调用能够通过 :{ println("lambda interface:$it")} 替换OnClickListener作为testClick1的参数

 

如果SAM转换存在歧义该如何消除

1、这里有两个java接口

    public interface OnClickListener {
        void onClick(String v);
    }

    public interface OnClickListener2 {
        void onClick(String v);
    }

还有两个对应的kotlin的函数,参数分别是上述的OnClickListener和OnClickListener2

fun testClick1(clickListener: OnClickListener) {
    clickListener.onClick("kkqqq")
}
// 这里使用重载testClick1函数
fun testClick1(clickListener: OnClickListener2) {
    clickListener.onClick("kkqqq")
}

如果直接调用:testClick1 {println("lambda interface:$it")} 则会提示:Overload resolution ambiguity.

这里的正确调用:

方法一:使用lambda的方式:testClick1 (OnClickListener{println("lambda interface:$it")}) 该方法首先创建了一个`OnClickListener`的匿名实例,然后对其唯一的方法进行了实现。

方法二:使用匿名的内部类方式

    testClick1(object: OnClickListener {
        override fun onClick(v: String?) {
            println("lambda interface:$v")
        }
    })

方法三、testClick ({it: String -> println("lambda interface:$it")} as OnClickListener) 但是这个方法在运行的时候提示:cannot be cast to class OnClickListener。原因是因为:在Kotlin中,不能直接将Lambda表达式强制类型转换为Java SAM接口,即使该接口是一个函数接口