lambda表达式:
new Thread(()-> System.out.println("Hello World!")).start();
为什么要使用lambda表达式?
Functional Interface(函数式接口)
public interface Runnable { public abstract void run(); }
函数式接口的推导
首先定义一个函数式接口
interface MyInterface { abstract void MyFunction(String str); }
若要实现这个接口,正常情况下我们需要写一个接口实现类,然后通过new这个类的对象来调用其中的方法:
//实现函数式接口 class MyClass implements MyInterface { @Override public void MyFunction(String str) { System.out.println(str); } } public class TestLambda { public static void main(String[] args) { //通过接口new一个MyClass对象,然后调用方法 MyInterface myInterface = new MyClass(); myInterface.MyFunction("接口实现类方法"); } }
为了调用接口中的方法,需要单独定义一个接口的实现类,不是很方便,于是在我们在同一个类中定义静态内部类:
public class TestLambda { //定义静态内部内 static class MyClass2 implements MyInterface { @Override public void MyFunction(String str) { System.out.println(str); } } public static void main(String[] args) { //创建MyClass2对象调用方法 MyInterface myInterface = new MyClass2(); myInterface.MyFunction("静态内部类方法"); } }
可以看到,MyClass2定义在方法外面,依然有些繁琐,于是我们开始使用局部内部类:
public class TestLambda { public static void main(String[] args) { //定义在函数内的局部内部类 class MyClass3 implements MyInterface { @Override public void MyFunction(String str) { System.out.println(str); } } //创建MyClass3对象调用方法 MyInterface myInterface = new MyClass3(); myInterface.MyFunction("局部内部类方法"); } }
为了进一步简化,我们还可以使用匿名内部类:
public class TestLambda { public static void main(String[] args) { //创建匿名内部类调用方法 new MyInterface() { @Override public void MyFunction(String str) { System.out.println(str); } }.MyFunction("匿名内部类方法"); } }
演化到这里,代码已经很精简了,但是依然有繁琐的代码导致核心代码依然不突出,为了进一步简化,只突出核心代码,我们使用了lambda来简化:
接口 = (参数列表) -> {
代码;
};
其中,参数列表依据函数式接口中的方法参数而定,可以没有,也可以有多个
lambda表达式使代码达到了最简,只保留了接口名,参数和执行体
public class TestLambda { public static void main(String[] args) { MyInterface myInterface = (String str) -> System.out.println(str); myInterface.MyFunction("lambda表达式方法"); } }
到此,我们清楚了lambda表达式的由来,最终的效果是我们定义一个函数式接口,通过一句lambda表达式就能调用里面的方法。lambda表达式使代码达到了最精简,只突出核心语句,去掉了没有意义的代码。
public class TestLambda { public static void main(String[] args) { MyInterface myInterface = (String str) -> System.out.println(str); myInterface.MyFunction("lambda表达式方法"); } } //定义一个函数式接口 interface MyInterface { abstract void MyFunction(String str); }
不知大家是否发现,文章最开头给出的代码是带new关键字的,我们用自己写的函数式接口不能用lambda函数作为参数把对象new出来,不知大家是否陷入了疑惑。别忘了,接口是不能被实例化的!如果一个接口能被实例化,只能说明他不是一个接口,而是一个类!
事实上,文章开头给出的lambda表达式
new Thread(()-> System.out.println("Hello World!")).start();
是一个匿名内部类,Thread并不是函数式接口,而是函数式接口Runnable的实现类,因为接口是不能被实例化的,若Thread是函数式接口则不能使用new关键字创建对象。根据上述推理lambda的过程向上倒推,我们会发现实际上上述语句等价于:
new Thread() { @Override public void run() { System.out.println("Hello World!"); } }.start();
通过查看Java源码可以看到,Thread类中存在接收一个参数的构造方法,而start()方法调用了start0()方法,start0()又调用了run()方法,因此上述代码又相当于:
new Thread() { @Override public void run() { System.out.println("Hello World!"); } }.run();
实际测试运行结果也确实相同,到这里我们不难看出,这就是一个实现了一个接口并重写接口中方法的匿名内部类。
那么新问题又来了,为什么说lambda表达式只支持函数式接口,是不是意味着函数式接口和实现了函数式接口的类都能用lambda表达式?事实上,lambda表达式作为参数值时,只需要形参类型为函数式接口即可,与类是否实现函数式接口无关。
public class Test02 { public static void main(String[] args) { //构造匿名内部类,lambda表达式作为参数 new TestClass(() -> System.out.println("AAAA")) { @Override void tests() { System.out.println("BBBB"); } }.tests(); } } //TestClass类并没有实现Runnable接口 class TestClass { //构造方法,接收参数类型为函数式接口Runnable public TestClass(Runnable runnable) { } void tests() { System.out.println("CCCC"); } }
当然,该段代码纯属为了搞清楚语法规则,并没有实际意义。因此,lambda表达式只支持函数式接口(只有一个抽象方法的接口)是因为lambda表达式作为参数时,只能用函数式接口作为形参来接收。
本人仅仅是因为对Java中的lambda感兴趣进行研究后的记录,把结果记录并分享出来,如果对大家有任何帮助我感到万分荣幸,因个人水平有限,文章中可能存在错误或者不正确的观点,欢迎大家批评指出。