SAM 和匿名函数的区别
Difference between SAM and anonymous functions
我最近在 Java 中偶然发现了 SAM(单一抽象方法)的概念。
我在 Scala 中编程,对我来说,它们看起来与匿名函数(或 lambda)相同,但是我的 IntelliJ 建议我在不同的场景中使用 SAM 或 lambda。
示例 1:
val x = new Function1[Int, Int] { // here usage of lambda is suggested
override def apply(x: Int): Int = x * 2
}
此处建议使用 lambda。
示例 2:
val event: EventHandler[ActionEvent] = new EventHandler[ActionEvent]() { // here usage of SAM is suggested
override def handle(e: ActionEvent): Unit = {
println("hi")
}
}
我很难看出匿名函数和 SAM 之间的语法差异。两者在概念上或功能上有什么区别吗?
FunctionN 类型在 scala 中是特殊的,因为匿名函数被自动推断为该类型。 val twice = (x: Int) => x * 2
被推断为 Function1[Int, Int]
,而不是任何其他类型,除非预期类型是(不同的)SAM 接口。
如果预期类型是 SAM 接口——具有单个抽象方法的接口——它将转换为该类型。
语法几乎相同,区别在于上下文。
函数是语言支持的接口,它允许将 2 个函数组合成一个函数,由集合等支持。
Single Abstract Method 是任何 trait 或 class,它只有一个方法来实现,因此采用此方法的签名,将其转换为函数的签名并让编译器将此类函数重写为匿名 class 实例。
明显差异:
- 编译器只能将函数重写到 SAM 中,前提是您提供的类型明显表明您不想在 SAM 中使用函数
- SAM 不会扩展函数接口,因此您将无法执行诸如
sam1 andThen sam2
除非您自己以某种方式在其中添加这些方法
- 您不能只获取某些东西返回的函数并将其用作 SAM - 函数语法必须用于初始化 SAM 对象,在创建它的地方
我想您可以将它们视为同一个概念 - 一些 trait/class 仅具有一个使用函数语法初始化的抽象方法 - 其中一些 FunctionX
接口将是“默认”并且编译器会插入它,而其他一些实现将需要显式类型归属并称为 SAM。
无论我们将 SAM 视为函数语法的重用,还是将函数视为 SAM 的特例,都不会改变 SAM 不是 lambdas/closures/anonymous 函数的事实。此名称仅用于打算用作函数的事物,即函数接口的实现(Function1
、Function2
、...、PartialFunction
等)。
我最近在 Java 中偶然发现了 SAM(单一抽象方法)的概念。
我在 Scala 中编程,对我来说,它们看起来与匿名函数(或 lambda)相同,但是我的 IntelliJ 建议我在不同的场景中使用 SAM 或 lambda。
示例 1:
val x = new Function1[Int, Int] { // here usage of lambda is suggested
override def apply(x: Int): Int = x * 2
}
此处建议使用 lambda。
示例 2:
val event: EventHandler[ActionEvent] = new EventHandler[ActionEvent]() { // here usage of SAM is suggested
override def handle(e: ActionEvent): Unit = {
println("hi")
}
}
我很难看出匿名函数和 SAM 之间的语法差异。两者在概念上或功能上有什么区别吗?
FunctionN 类型在 scala 中是特殊的,因为匿名函数被自动推断为该类型。 val twice = (x: Int) => x * 2
被推断为 Function1[Int, Int]
,而不是任何其他类型,除非预期类型是(不同的)SAM 接口。
如果预期类型是 SAM 接口——具有单个抽象方法的接口——它将转换为该类型。
语法几乎相同,区别在于上下文。
函数是语言支持的接口,它允许将 2 个函数组合成一个函数,由集合等支持。
Single Abstract Method 是任何 trait 或 class,它只有一个方法来实现,因此采用此方法的签名,将其转换为函数的签名并让编译器将此类函数重写为匿名 class 实例。
明显差异:
- 编译器只能将函数重写到 SAM 中,前提是您提供的类型明显表明您不想在 SAM 中使用函数
- SAM 不会扩展函数接口,因此您将无法执行诸如
sam1 andThen sam2
除非您自己以某种方式在其中添加这些方法 - 您不能只获取某些东西返回的函数并将其用作 SAM - 函数语法必须用于初始化 SAM 对象,在创建它的地方
我想您可以将它们视为同一个概念 - 一些 trait/class 仅具有一个使用函数语法初始化的抽象方法 - 其中一些 FunctionX
接口将是“默认”并且编译器会插入它,而其他一些实现将需要显式类型归属并称为 SAM。
无论我们将 SAM 视为函数语法的重用,还是将函数视为 SAM 的特例,都不会改变 SAM 不是 lambdas/closures/anonymous 函数的事实。此名称仅用于打算用作函数的事物,即函数接口的实现(Function1
、Function2
、...、PartialFunction
等)。