Lambda 表达式(Lambda expression)是一个匿名函数,基于数学中的λ演算得名,也可称为闭包(Closure)。现在很多语言都支持 Lambda 表达式,如 C++、C#、Java、 Python 和 JavaScript 等。Lambda 表达式是推动 Java 8 发布的重要新特性,它允许把函数作为一个方法的参数(函数作为参数传递进方法中)
下面通过下面这个例子来理解 Lambda 表达式的概念 :
public class LambdaDemo {//函数定义public void printSomething(String something) {System.out.println(something);}//通过创建对象调用函数public static void main(String[] args) {LambdaDemo demo = new LambdaDemo();String something = "I am learning Lambda";demo.printSomething(something);}
}
这是经典OOP实现。下面我们对上面代码做一个修改,创建一个功能接口,并对该接口定义抽象方法。
public class LambdaDemo {//抽象功能接口interface Printer {void print(String val);}//通过参数传递功能接口public void printSomething(String something, Printer printer) {printer.print(something);}public static void main(String[] args) {LambdaDemo demo = new LambdaDemo();String something = "I am using a Functional interface";//实现Printer接口Printer printer = new Printer() {@Overridepublic void print(String val) {//控制台打印System.out.println(val);}};demo.printSomething(something, printer);}
}
至此我们都尚未使用lambda表达式。我们仅创建了Printer接口的具体实现,并将其传递给printSomething 方法。下面将使用lambda表达式重构一下上面的代码。
关于lambda表达式的语法:
形参列表=>函数体(函数体多于一条语句的可用大括号括起) 在Java里就是() -> {}:
(param1,param2,param3 ...,paramN)- > { //代码块; }
- lambda表达式,表达的是接口函数
- 箭头左侧是函数的逗号分隔的形式参数列表
- 箭头右侧是函数体代码
package com.example.exceldemo.task;
public class LambdaDemo {//抽象功能接口interface Printer {void print(String val);}//通过参数传递功能接口public void printSomething(String something, Printer printer) {printer.print(something);}public static void main(String[] args) {LambdaDemo demo = new LambdaDemo();String something = "I am learning Lambda";//实现Printer接口(请关注下面这行lambda表达式代码)Printer printer = System.out::println;//调用接口打印demo.printSomething(something, printer);}
}
当然这两种写法是完全一样的:
Printer printer = (String toPrint)->{System.out.println(toPrint);};
Printer printer = System.out::println;
补充:
Java 8 之后增加了双冒号::
运算符,该运算符用于“方法引用”,注意不是调用方法。“方法引用”虽然没有直接使用 Lambda 表达式,但也与 Lambda 表达式有关,与函数式接口有关。 方法引用的语法格式如下:
ObjectRef :: methodName
其中,ObjectRef 是类名或者实例名,methodName 是相应的方法名。
方法引用可以理解为 Lambda 表达式的快捷写法,它比 Lambda 表达式更加的简洁,可读性更高,有很好的重用性。如果实现比较简单,复用的地方又不多,推荐使用 Lambda 表达式,否则应该使用方法引用。
lambda表达式使我们代码更简洁。实际上使用lambda表达式在性能和多核处理还有更多的好处,但是只有在理解java8 Streams API之后它们才有意义,因此不在本文讨论范围之内。
对比传统java代码的实现方式,代码量是不是减少了很多?但这仍不是最简实现方式,我们一步一步来。
Printer printer = (String toPrint)->{System.out.println(toPrint);};
//简化:去掉参数类型
Printer printer = (toPrint)->{System.out.println(toPrint);};
//简化:去掉参数括号
Printer printer = toPrint->{System.out.println(toPrint);};
//简化:去掉函数体花括号
Printer printer = toPrint->System.out.println(toPrint);
- 即使没有在箭头的左侧指定参数的类型,编译器也会从接口方法的形式参数中推断出其类型
- 当只有一个参数的时候,我们完全可以省略参数的括号
- 当函数体只有一行的时候,我们完全可以省略函数体花括号
如果我们的接口方法定义不带任何参数,则可以用空括号替换:
()-> System.out.println("anything you wan to print")
那么,我们最终通过lambda表达式,简化完成的代码是什么样的呢?庐山真面目:
public static void main(String[] args) {LambdaDemo demo = new LambdaDemo();String something="I am Lambda";//关注下面的这行代码demo.printSomething(something, toPrint -> System.out.println(toPrint));
}
我们使用lambda表达式内联为函数调用参数,将最初main方法的9行代码下降到只有3行。但笔者要说,这仍然不是lambda表达式可以完成的最终极代码简化方式,当你学习了java8 Stream API结合lambda表达式使用,你会发现你的编码效率将大幅度提高。