我听说lambdas即将到达你附近的Java(J8)。我在一些博客上找到了一个例子:
SoccerService soccerService = (teamA, teamB) -> {
SoccerResult result = null;
if (teamA == teamB) {
result = SoccerResult.DRAW;
}
else if(teamA < teamB) {
result = SoccerResult.LOST;
}
else {
result = SoccerResult.WON;
}
return result;
};
马上就开始了:
teamA
和teamB
在哪里输入?或者不是它们(就像一些奇怪的仿制药一样)?答案 0 :(得分:15)
有关该示例的完整版本,请参阅this page(但相关部分如下所示)。
这些类型是从SoccerService接口和SoccerResult枚举中推断出来的,未在您的代码段中显示:
enum SoccerResult{
WON, LOST, DRAW
}
interface SoccerService {
SoccerResult getSoccerResult(Integer teamA, Integer teamB);
}
lambda与标准匿名类的好处只是减少了冗长:
(x, y) => x + y
与之类似:
new Adder()
{
public int add(int x, int y)
{
return x + y;
}
}
关于闭包和lambda之间的区别,请参阅this question。
答案 1 :(得分:15)
Lambda表达式只是实现目标接口的语法糖,这意味着您将通过lambda表达式在接口中实现特定方法。编译器可以推断出接口中参数的类型,这就是你不需要在lambda表达式中明确定义它们的原因。
例如:
Comparator<String> c = (s1, s2) -> s1.compareToIgnoreCase(s2);
在这个表达式中,lambda表达式显然实现了Comparator
个字符串,因此,这意味着lambda表达式是用于实现compare(String, String)
的语法糖。
因此,编译器可以安全地假设s1
和s2
的类型为String
。
您的目标接口类型提供了编译器确定lambda参数的实际类型所需的所有信息。
Oracle Corportion的Java语言架构师Briant Goetz在JDK 8 Lambdas上发表了一些正在进行的工作。我相信你的问题的答案就在那里:
第二篇文章解释了如何在字节码级别实现lambda表达式,并可以帮助您深入研究第二个问题的细节。
答案 2 :(得分:9)
Lambda使用目标类型,非常类似于泛型方法调用(自1.5起)和菱形[not a]运算符(自1.7起)。粗略地说,表示(或可以推断)应用结果的类型,用于提供单一抽象方法(SAM)基类型的类型,从而提供方法参数类型。
作为1.5中通用方法推理的一个例子:
Set<Team> noTeams = Collections.emptySet();
1.7中的钻石操作员:
Set<Team> aTeams = new HashSet<>();
团队,团队,团队,团队,团队,团队。我甚至喜欢说团队这个词。
lambda是一种有限形式的闭包,与匿名内部类几乎完全相同,但有一些随机差异可以解决这个问题:
外部this
未被内部this
隐藏。这意味着lambda和匿名内部类中的相同文本可以表示巧妙但完全不同的事物。这应该让Stack Overflow忙于奇怪的问题。
为了弥补内部this
的缺失,如果直接分配给局部变量,则可以在lambda中访问该值。 IIRC(我可以检查,但不会),在一个匿名内部类中,本地将在范围内并在外部范围中隐藏变量,但您不能使用它。我相信缺少实例初始化器会使这更容易指定。
本地字段不会被标记为final
但可能会被视为final
。所以它们不在范围内,但你实际上可以阅读(尽管不是写)。
更简洁的语法。就是这样。
当然,Java语法的其余部分和以前一样糟透了。
我不相信这是在初始实现中,但不是作为[内部]类实现,lambdas可以使用方法句柄。方法句柄的性能略低于早期的预测。废除类,应该减少字节码占用空间,可能减少运行时占用空间和类加载时间。可能存在一种实现,其中大多数匿名内部类(不是Serializable
,简单的静态初始化器)没有经历构思不良的类加载机制而没有任何特别明显的不兼容性。
(希望我的术语隐藏正确。)