只有一个抽象方法的接口被称为函数接口,或者称为单一抽象方法(SAM)接口。函数接口可以有多个非抽象成员,但只能有一个抽象成员。
fun interface KRunnable {
fun invoke()
}
SAM转换
对于函数接口,你可以使用SAM转换来通过lambda
表达式使你的代码更简洁、可读
与手动创建实现函数接口的类不同,你可以使用lambda
表达式。通过SAM转换,kotlin
可以将任何与接口的单一方法签名匹配的lambda
表达式转换为代码,动态实例化接口实现。
函数接口
fun interface IntPredicate {
fun accept(i: Int): Boolean
}
非SAM转换方式实现
val isEven = object : IntPredicate {
override fun accept(i: Int): Boolean {
return i % 2 == 0
}
}
fun main() {
println(isEven.accept(7))
}
使用SAM转换方式实现
val isEven = IntPredicate { it % 2 == 0 }
fun main() {
println(isEven.accept(7))
}
lambda
表达式可以替换所有非必要的代码
从带有构造函数的接口转移到函数式接口
从1.6.20
版本开始,kotlin
支持对函数接口构造函数的可调用引用,这为从具有构造函数功能的接口迁移到函数接口提供了一种兼容的方式
对于旧代码
interface Printer {
fun print()
}
// 当前方法定义了带有一个参数(类型为函数类型)的函数,用于创建实现了Printer接口的匿名类的实例
fun Printer(block: () -> Unit): Printer = object : Printer { override fun print() = block() }
fun main() {
Printer{ print("打印日志") }.print()
}
启用了对函数接口构造函数的可调用引用后
fun interface Printer {
fun print()
}
fun main() {
Printer{ print("打印日志") }.print()
}
它的构造函数将会隐式创建,并且使用::Printer
函数引用的任何代码都将编译通过
fun interface Printer {
fun print()
}
fun main() {
print(::Printer) // fun interface com.example.Printer
}
通过使用 @Deprecated
注解和 DeprecationLevel.HIDDEN
,保留对旧函数 Printer
的二进制兼容性
fun interface Printer {
fun print()
@Deprecated(message = "Your message about the deprecation", level = DeprecationLevel.HIDDEN)
fun Printer(block: () -> Unit): Printer = object : Printer { override fun print() = block() }
}
函数接口和类行别名
也可以通过使用函数类型的类型别名来简单地重写上述代码
对于
fun interface IntPredicate {
fun accept(i: Int): Boolean
}
val isEven = IntPredicate { it % 2 == 0 }
fun main() {
println(isEven.accept(7))
}
使用类型别名实现
typealias IntPredicate = (i: Int) -> Boolean
val isEven: IntPredicate = { it % 2 == 0 }
fun main() {
println(isEven(7))
}
函数接口和类型别名有不同的用途。类型别名只是现有类型的名称,它们不创建新的类型(typealias IntPredicate = (i: Int) -> Boolean
中,IntPredicate
只是 (i: Int) -> Boolean
函数类型的别名,没有创建新的数据类型),而函数接口则会创建新的类型。可以为特定的函数接口提供扩展,以使其对普通函数或其类型别名不适用。
类型别名只能有一个成员,而函数接口可以有多个非抽象成员和一个抽象成员。函数接口还可以实现和扩展其他接口。
函数接口比类型别名更灵活,提供更多功能,但它们在语法和运行时方面可能更麻烦,因为它们可能需要转换为特定的接口。