λ表达式的基本用途
回调与Java8的λ表达式 说明了Java8的λ表达式的基本用途:完成了回调的原意——代码的参数化。
回调:可以简单地说,如果你的方法需要override底层或JDK的某个类的方法,而且你从来没有自己调用过该方法,则该方法(有时候,也指被改写的方法)就是回调。例如
- Applet定义的init()、start()、stop()和destroy();
- 图形绘制方法paint(Graphics)、update(Graphics)和重载的repaint();
- java.lang.Runnable的run();
- GUI中ActionListener的actionPerformed(ActionEvent e)...
在Java8之前,回调的代码通常由匿名类提供,如下代码(完整代码见回调与Java8的λ表达式 )
s.register(new IClient(){
@Override public void callback(int i){
System.out.println("==" + i + "0%");
}
});
现在则可以:
IClient listener1=(i)->{System.out.println("+" + i + "0%");};
s.register(listener1);
s.register((i)->{System.out.println("++" + i + "0%");});
显然,使用λ表达式提供回调代码较匿名类简洁,较Client implements IClient简洁得更多。
因为IClient是仅有一个抽象方法的接口,既然唯一的抽象方法是
public void callback(int i);
那么,而编译器将赋值给IClient类型变量如listener1的“某λ表达式”,识别为给那个唯一的抽象方法提供方法体的匿名实现类的引用。从代码输入的角度,λ表达式就可以尽可能的简单。
- IClient listener1= (int i)->{System.out.println("+" + i + "0%");};
//IClient的唯一的抽象方法的方法名不需要了,肯定为callback提供方法体。也不能要方法名,λ表达式的三部分,容不下方法名。 - listener1=(i)->{/**/};
//可以省略i的类型,编译器从唯一的抽象方法的形参列表中可以推导类型 - listener1=i->{};
//只有单一的形参的时候,可以省略λ表达式的形参括号。
其他情况,你可以按照敲代码最少的原则,自己试一试。例如
- (参数列表)部分:有多个参数时,可以(int i,int j)、(i,j);一个参数,(i)、i->;无参数,()->
如int getX()。其λ表达式为 ()->{return 0;} 或 ()->0;
//yqj2065还想在无参数时省略形参括号,如同“->0”, - {一个代码块}部分:多个语句时,方法体;void方法,方法体;有返回值的单一语句,如int add(int i,int j)。其λ表达式为(i,j)->{return i+j;} 或 (i,j)->i+j;
函数接口
为什么能够写出- IClient listener1=某λ表达式;
- s.register(某λ表达式);
因为IClient是仅有一个抽象方法的接口——函数(型)接口(functional interface)。
- IClient listener1=某λ表达式;
编译器解读为 某λ表达式 为IClient的仅有抽象方法提供代码。虽然IClient“是一个”Object,可以
Object obj= listener1;
但是,
Object obj= 某λ表达式;
感觉上就不太靠谱,“某λ表达式”是为谁的仅有抽象方法提供代码呢?so,
Object obj= (IClient)某λ表达式;//ok - s.register(某λ表达式);
因为按照register(IClient listener),编译器知道 某λ表达式 为IClient的仅有抽象方法提供代码。
函数接口只能够有一个抽象方法。假设IClient继承Runnable,又想作为函数接口@FunctionalInterface,就得给继承过来的run()提供方法体(这里给一个空方法体凑数)。
package Lower;
/**
* @author yqj2065
*/
@FunctionalInterface
public interface IClient extends Runnable{
int add(int i,int j);
@Override default public void run(){};
}
函数接口(一般地,普通接口)中 使用 default关键字,可以 添加具有 实现的 方法,这个玩意就是Java接口的默认方法。
在函数接口中出现默认方法,好像有点理由;一般接口中使用默认方法,参考纠结的默认方法。