muf*_*fin 35 java syntax lambda java-8
请解释Java 8的lambda方法的语法.
有很多解释了那里什么拉姆达功能,但我找不到语法的详尽的解释,而我发现很难学会正确复制的语法,因为我不明白为什么他们"按原样重写.
这是我遇到的一个常见案例,由NetBeans提供:
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new MainAppJFrame();
});
}
Run Code Online (Sandbox Code Playgroud)
所以,不知何故,以下lambda表达式正在解析为匿名Runnable对象的run()方法:
() -> {
// do stuff
}
Run Code Online (Sandbox Code Playgroud)
这->是lambda语法,对吧?花括号只是包含匿名方法代码.括号是否为空参数,因为在这种情况下我们正在创建一个Runnable.run()方法?
这一点对我来说都不太清楚.我假设编译器知道Runnable根据SwingUtilities.invokeLater(Runnable)方法预期的类型实例化匿名?如果有两种SwingUtilities.invokeLater方法仅在参数列表中有所不同,会发生什么?显然在这个特定情况下没有,但在其他地方可能:
interface ExampleLambdaConsumer {
public void doSomething(Runnable r);
public void doSomething(java.lang.reflect.Method m);
}
class C implements ExampleLambdaConsumer {
// implementations for doSomething methods here
public static void main(String[] args) {
doSomething(() -> {
// lambda method body here
}
}
}
Run Code Online (Sandbox Code Playgroud)
Kar*_*l S 43
语法是:
arguments -> body
Run Code Online (Sandbox Code Playgroud)
哪里arguments都可以
()
如果可以从上下文中推断出该变量的类型,则为单个变量
括号中包含或不包含类型的变量序列
和body可以是表达式,也可以是var带语句的块.简单地返回表达式,即(x)等同于(x, y)
编辑:如果lambda表达式如下(int x, int y):
如果(var x, var y)返回(int x, y),它们相当于(x, var y)
否则,它们相当于(var x, int y)或body.编译器从调用上下文推断出它,但通常它会更喜欢后者.
因此,如果您有两种方法:{...}和() -> 2,那么:
() -> {return 2;}并() -> f()打电话给第一个,
f() 将拨打第二个,并且
void:
如果() -> { f(); }返回() -> { f(); }或者不可转换的类型() -> { return f(); }),那么它将调用第二个
如果void handle(Supplier<T>)返回一个可转换为的类型void handle(Runnable),那么它将调用第一个类型
编译器尝试将lambda的类型与上下文匹配.我不知道确切的规则,但答案是:
如果有两个SwingUtilities.invokeLater方法只在参数列表中有所不同,会发生什么?
是:它取决于那些参数列表.如果handle(() -> { return f(); })另一个参数只有一个参数,并且该参数的类型也是一个类型的方法的接口handle(() -> x),那么它会抱怨它无法找出你的意思.
他们为什么这样写?好吧,我认为这是因为C#和Scala中的语法几乎相同(他们使用handle(() -> { f(); }而不是handle(() -> f())).
Xab*_*ter 10
语法是
(parameter_list_here) -> { stuff_to_do; }
Run Code Online (Sandbox Code Playgroud)
如果花括号是单个表达式,则可以省略花括号.如果参数列表是单个参数,则可以省略参数列表周围的常规括号.
该语法仅适用于所有功能接口.@FunctionalInterface注释告诉编译器您打算编写这样的接口,并在不满足要求时给出编译错误 - 例如,它必须只有1个可重写的方法.
@FunctionalInterface
interface TestInterface {
void dostuff();
}
Run Code Online (Sandbox Code Playgroud)
Runnable也是这样宣布的.其他接口不是,它们不能与lambda函数一起使用.
现在我们已经使用不带参数的方法创建了一个新的功能接口,我们如何测试签名中有关"碰撞"的问题?
public class Main {
private void test(Runnable r) {
}
private void test(TestInterface ti) {
}
public static void main(String[] args) {
test(() -> { System.out.println("test");})
}
@FunctionalInterface
interface TestInterface {
void dostuff();
}
}
Run Code Online (Sandbox Code Playgroud)
结果:编译错误:对方法测试进行严格调用.
您看,编译器/ VM(如果完成运行时)找到适当的方法及其参数列表,并查看参数是否是功能接口,如果是,则创建该接口的匿名实现.从技术上讲(在字节代码中)它与匿名类不同,但在其他方面相同(您将看不到Main $ 1.class文件).
您的示例代码(由Netbeans提供)也可以替换为
SwingUtilities.invokeLater(MainAppJFrame::new);
Run Code Online (Sandbox Code Playgroud)
顺便说一句.:)
Lambda表达式基本上在Java 8中采用,以简化作为匿名函数覆盖进程函数.
它们只是覆盖旧java匿名函数的快捷方式.
请参考以下示例:
假设您有接口A,它只有一个声明如下的方法:
interface A{
void print();
}
Run Code Online (Sandbox Code Playgroud)
现在使用旧的java风格,我们将以匿名的方式覆盖它,如下所示:
new A() {
@Override
public void print() {
System.out.println("in a print method");
}
};
Run Code Online (Sandbox Code Playgroud)
另外现在使用java 8 lambda表达式,我们将使用它如下:
() -> System.out.println("in a print method");
Run Code Online (Sandbox Code Playgroud)
在这里我们可以在->操作符之前传递方法所需的参数,然后在操作符之后覆盖body ->.
我们需要实现的唯一设置是我们需要使用@FunctionalInterface声明接口, 如下所示:
@FunctionalInterface
interface A{
void print();
}
Run Code Online (Sandbox Code Playgroud)
注意: - lambda表达式只能用于只有一个非默认方法的"功能"接口.