Java Lambda 和闭包
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11404218/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java Lambdas and Closures
提问by IAmYourFaja
I hear lambdas are coming soon to a Java near you (J8). I found an example of what they will look like on some blog:
我听说 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;
};
So right off the bat:
所以马上:
- Where are
teamA
andteamB
typed? Or aren't they (like some weird form of generics)? - Is a lambda a typeof closure, or is it the other way around?
- What benefits will this give me over a typical anonymous function?
- 在哪里
teamA
和teamB
打字?或者它们不是(就像某种奇怪的泛型形式)? - lambda 是一种闭包,还是相反?
- 与典型的匿名函数相比,这会给我带来什么好处?
采纳答案by Edwin Dalorzo
The Lambda expression is just syntactic sugar to implement a target interface, this means that you will be implementing a particular method in the interface through a lambda expression. The compiler can infer the types of the parameters in the interface and that's why you do not need to explicitly define them in the lambda expression.
Lambda 表达式只是实现目标接口的语法糖,这意味着您将通过 lambda 表达式在接口中实现特定方法。编译器可以推断接口中参数的类型,这就是您不需要在 lambda 表达式中显式定义它们的原因。
For instance:
例如:
Comparator<String> c = (s1, s2) -> s1.compareToIgnoreCase(s2);
In this expression, the lambda expression evidently implements a Comparator
of strings, therefore, this implies the lambda expression is syntactic sugar for implementing compare(String, String)
.
在这个表达式中,lambda 表达式显然实现了 aComparator
的字符串,因此,这意味着 lambda 表达式是实现 的语法糖compare(String, String)
。
Thus, the compiler can safely assume the type of s1
and s2
is String
.
因此,编译器可以安全地假定的类型s1
和s2
为String
。
Your target interface type provides all the information the compiler needs to determine what are the actual types of the lambda parameters.
您的目标接口类型提供了编译器确定 lambda 参数的实际类型所需的所有信息。
Briant Goetz, Java Language Architect at Oracle Corportion has published a couple of articles of the work in progress in JDK 8 Lambdas. I believe the answers to your questions are there:
Oracle 公司的 Java 语言架构师 Briant Goetz 发表了几篇关于 JDK 8 Lambdas 正在进行的工作的文章。我相信你的问题的答案就在那里:
- State of Lambda.
- State of Lambda Libraries Edition.
- Translation of Lambda Expressions
- JVMLS 2012: Implementing Lambda Expressions in Java
This second article explains how the lambda expressions are implemented at the bytecode level and may help you delve into the details of your second question.
第二篇文章解释了如何在字节码级别实现 lambda 表达式,并可能帮助您深入研究第二个问题的细节。
回答by DNA
See this pagefor a full version of that example (however, the relevant parts are shown below).
有关该示例的完整版本,请参阅此页面(但是,相关部分如下所示)。
The types are inferred from the SoccerService interface and SoccerResult enum, not shown in your snippet:
这些类型是从 SoccerService 接口和 SoccerResult 枚举推断的,未显示在您的代码段中:
enum SoccerResult{
WON, LOST, DRAW
}
interface SoccerService {
SoccerResult getSoccerResult(Integer teamA, Integer teamB);
}
The benefit (of lambdas versus standard anonymous classes) is just reduced verbosity:
好处(lambdas 与标准匿名类相比)只是减少了冗长:
(x, y) => x + y
versus something like:
与类似的东西:
new Adder()
{
public int add(int x, int y)
{
return x + y;
}
}
For the difference between a closure and a lambda, see this question.
有关闭包和 lambda 之间的区别,请参阅此问题。
回答by Tom Hawtin - tackline
- Where are teamA and teamB typed? Or aren't they (like some weird form of generics)?
- teamA 和 teamB 在哪里输入?或者它们不是(就像某种奇怪的泛型形式)?
Lambda's use target typing, much like generic method calls (since 1.5) and the diamond [not an] operator (since 1.7). Roughly, where the type the result applied to is stated (or can be inferred) that is used to supply the type of the Single Abstract Method (SAM) base type and hence the method parameter types.
Lambda 使用目标类型,很像泛型方法调用(自 1.5 起)和菱形 [not an] 运算符(自 1.7 起)。粗略地说,应用结果的类型被声明(或可以推断),用于提供单一抽象方法 (SAM) 基类型的类型,从而提供方法参数类型。
As an example of generic method inference in 1.5:
作为 1.5 中泛型方法推断的示例:
Set<Team> noTeams = Collections.emptySet();
And diamond operator in 1.7:
1.7 中的菱形运算符:
Set<Team> aTeams = new HashSet<>();
Team, team, team, team, team, team. I even love saying the word team.
团队,团队,团队,团队,团队,团队。我什至喜欢说团队这个词。
- Is a lambda a type of closure, or is it the other way around?
- lambda 是一种闭包,还是相反?
A lambda is a limited form of closure in almost exactly the same way as anonymous inner classes, but with some random differences to catch you out:
lambda 是一种有限形式的闭包,其方式与匿名内部类几乎完全相同,但有一些随机差异可以让您发现:
The outer this
is not hidden by an inner this
. This means that the same text in a lambda and an anonymous inner class can mean subtly but completely differentthings. That should keep Stack Overflow busy with odd questions.
外部this
没有被内部隐藏this
。这意味着 lambda 和匿名内部类中的相同文本可能意味着微妙但完全不同的事情。这应该让 Stack Overflow 忙于解决奇怪的问题。
To make up for the lack of inner this
, if assigned directly to a local variable, then that value is accessible within the lambda. IIRC (I could check, but wont), in an anonymous inner class the local will be in scope and hide variables in an outer scope but you can't use it. I believe the lack of an instance initialiser makes this much easier to specify.
为了弥补 inner 的不足this
,如果直接分配给局部变量,则可以在 lambda 内访问该值。IIRC(我可以检查,但不会),在匿名内部类中,本地将在范围内并在外部范围内隐藏变量,但您不能使用它。我相信缺少实例初始化器使得这更容易指定。
Local fields that do not happen to be marked final
but could be, are treated as if they are final
. So not are they in scope, but you can actually read (though not write) them.
碰巧没有被标记final
但可能被标记的本地字段被视为final
. 所以它们不在范围内,但您实际上可以读取(尽管不能写入)它们。
- What benefits will this give me over a typical anonymous function?
- 与典型的匿名函数相比,这会给我带来什么好处?
A briefer syntax. That's about it.
更简洁的语法。就是这样。
Of course the rest of the Java syntax is just as hopelessly bad as ever.
当然,Java 语法的其余部分与以往一样糟糕。
I don't believe this is in the initial implementation, but instead of being implemented as [inner] classes, lambdas can use method handles. The performance of method handles falls somewhat short of earlier predictions. Doing away with classes, should reduce bytecode footprint, possibly runtime footprint and certainly class loading time. There could be an implementation where most anonymous inner classes (not Serializable
, trivial static initialiser) didn't go through the poorly conceived class loading mechanism without any particularly noticeable incompatibilities.
我不相信这是在初始实现中,但 lambda 可以使用方法句柄,而不是作为 [内部] 类来实现。方法句柄的性能略低于早期的预测。取消类,应该减少字节码占用空间,可能是运行时占用空间,当然还有类加载时间。可能有一个实现,其中大多数匿名内部类(不是Serializable
,琐碎的静态初始化程序)没有通过构思不佳的类加载机制而没有任何特别明显的不兼容性。
(Hope I've got the terminology wrt hidingcorrect.)
(希望我的术语隐藏正确。)