Java中的“ SAM类型”是什么?


133

在阅读Java-8规范后,我不断看到对“ SAM类型”的引用。我还没有找到关于这是什么的明确解释。

什么是SAM类型?什么时候可以使用的示例场景是什么?


4
请参阅cr.openjdk.java.net/~briangoetz/lambda/lambda-state-3.html(在一次搜索后发现的问题,这使我想到了另一个SO问题)。
乔恩·斯基特

2
请不要让人们参考过时的信息。稍长的搜索将把您带到最新版本:cr.openjdk.java.net/~briangoetz/lambda/lambda-state-4.html,它本身已有 18个月的历史,现在在许多版本中已过时的地方。OP的问题可在lambdafaq.org/what-is-a-functional-interface上找到,该页面位于FAQ中的一页,我试图与最新发展的语言和API保持同步
莫里斯·纳夫塔琳

1
@MauriceNaftalin您也可以仅链接Java跟踪,该跟踪由开发团队更新。
布莱恩

1
当前术语是“功能接口”。
newacct

1
@MauriceNaftalin:对不起,错过了那个。如果找到了,肯定会链接到它。
乔恩·斯基特

Answers:


142

总结乔恩发布的链接1的情况下,它不断下降,“SAM”代表“单一抽象方法”和“SAM型”是指接口等RunnableCallable等Lambda表达式,在Java 8中的新功能,是被视为SAM类型,可以自由转换为它们。

例如,使用这样的接口:

public interface Callable<T> {
    public T call();
}

您可以这样声明Callable使用lambda表达式:

Callable<String> strCallable = () -> "Hello world!";
System.out.println(strCallable.call()); // prints "Hello world!"

在这种情况下,Lambda表达式主要只是语法糖。与匿名类相比,它们在代码上看起来更好,并且对方法命名的限制较少。从链接中获取以下示例:

class Person { 
    private final String name;
    private final int age;

    public static int compareByAge(Person a, Person b) { ... }

    public static int compareByName(Person a, Person b) { ... }
}

Person[] people = ...
Arrays.sort(people, Person::compareByAge);

这会创建一个Comparator使用与共享不同名称的特定方法,Comparator.compare这样您就不必遵循方法的接口命名,并且您可以在一个类中具有多个比较替代,然后通过即时创建比较器。 lambda表达式。

更深入...

在更深层次上,Java使用invokedynamicJava 7中添加的字节码指令来实现这些功能。我早些时候曾说过,声明Lambda会创建匿名类CallableComparable与匿名类相似的实例,但这并非完全正确。相反,第一次invokedynamic调用时,它将使用LambdaMetafactory.metafactory方法创建Lambda函数处理程序,然后在以后的Lambda调用中使用此缓存的实例。在此答案中可以找到更多信息。

这种方法很复杂,甚至包括可以直接从堆栈内存中读取原始值和引用以传递到您的Lambda代码中的代码(例如,解决需要分配Object[]数组来调用Lambda的情况),但是它允许Lambda实现的未来迭代替换旧的实现,而不必担心字节码兼容性。如果Oracle的工程师在较新版本的JVM中更改了基础Lambda实现,则在较旧JVM上编译的Lambdas将自动使用较新的实现,而开发人员无需进行任何更改。


1链接上的语法已过期。查看Lambda Expressions Java Trail,以了解当前语法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.