Lambda 是一个匿名函数, Lambda 表达式是一段可以传递的代码(将代码像数据一样进行传递)。
Lambda表达式其本质是函数式接口(只有一个抽象方法)的实例。
它是可传递的匿名函数的一种形式:它没有名称,但它有参数列表,函数主体,返回类型,可能还有一个可以抛出的异常列表。
Lambda 表达式基础语法:
Lambda表达式是Java 8 引入的一种新的语法,它以一种简洁的语法定义的语句块(代码块),常可作为函数接口实例使用。
Java引入了一个新的操作符“->”, 该操作符被称为 Lambda 操作符或箭头操作符。箭头操作符将 Lambda 分成了两个部分:
①左侧:是 Lambda 表达式的参数列表。
②右侧:是 Lambda 表达式的代码块(语句块,函数体),是函数式接口中抽象方法的方法体。
Lambda表达式有三个组成部分:参数列表、Lambda 操作符“->”、语句块。Lambda表达式的标准的语法格式如下:
(parameter-lis) -> {express-or-statements}
- 参数列表(parameter-lis):括号中的参数列表,有多个参数时以英文逗号分隔,如没有参数需要保留括号“()”,参数可以声明类型,通常不需要声明(编译器可以根据上下文推导获得)。
- Lambda 操作符(->):其作用是告诉编译器这是一个λ表达式。
- Lambda表达式的语句块:花括号“{}”中的express-or-statements表示是表达式或语句块,相当于方法体。特殊情形,当只有一条语句时,可以省略花括号“{}”和语句结尾处的分号“;”,把它作为一个表达式使用。
Lambda 表达式的语法格式:
- 格式一:无参数Lambda 表达式:表达式语法格式:() -> { 程序语句块 }
接口名和方法名都可以省略。无参数的Lambda表达式,必须保留空的括号“()”。更特殊的情形,当只有一行程序代码时,可简写为:() -> 表达式
无参数,无返回值的用法 示例:() -> System.out.println(“我是一个线程的Lambda版本”);
示例一:示例中Runnable r 采用匿名函数接口的版本;Runnable r1 使用Lambda 表达式版本。
public void test1() {
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("我是一个线程");
}
};
r.run();
Runnable r1 = () -> System.out.println("我是一个线程的Lambda版本");
r1.run();
}
示例二:一个更复杂的例程LambdaDemo:显示当前时间,每隔1秒显示一次日期时间。
请在电脑上调试一下,看看效果。
Java 7以前版本的匿名类写法版本
import java.util.Date;
import javax.swing.Timer;
public class LambdaDemo {
public static void main(String[] args) {
new Thread( new Runnable() {//灰底代码是个匿名类,Runnable是函数接口
@Override
public void run() //run是方法名
{
new Timer(1000, event->System.out.println("日期时间:" +new Date())).start(); }
} ).start();
while(true); //主线程无限循环
}
}
Lambda表达式版本:
Java 8引入了Lambda表达式,可写出更优雅的代码,可如下改写为无参数的λ表达式,效果完全相同:
import java.util.Date;
import javax.swing.Timer;
public class LambdaDemo {
public static void main(String[] args) {
new Thread( ()->{ //改写为λ表达式后,接口名和方法名都省略了。
new Timer(1000, event->System.out.println("日期时间:" +new Date())).start();
} ).start();
while(true); //主线程无限循环
}
}
单行的Lambda表达式,还可再精简;以下是最简版本写法,仔细瞧瞧又省略了啥:
注意:中间这行是表达式,不是语句,结尾处没有分号。有分号反而错了。
new Thread( ()->
new Timer(1000, event->System.out.println("日期时间:" +new Date())).start()
).start();
- 格式二:单个参数Lambda表达式:语法一般格式为:([类名]变量名)->{ 程序语句块 }
格式中的方括号表示里面的内容是可选的。通常,λ表达式参数类型可推导出来,可以省略类名和参数两边的括号“()”。如实现事件监听器的Lambda表达式示例:event -> { 程序语句块 }
当只有单条语句时,还可省略花括号,简写形式为:变量名->表达式
上例中的run方法体中Timer构造器的第二个参数就是单个参数λ表达式的例子,但入口参数event在表达式中没有用到。下面就是简写形式:
new Timer(1000, event->System.out.println("日期时间:" +new Date())).start();
对于打印显示的Lambda表达式:
(x) -> System.out.println(x); 或者 x -> System.out.println(x); 单个参数,可以省略参数的小括号。
public void test2(){
String message = "消费者Consumer函数式接口,有一个输入参数,无返回值";
Consumer<String> con = (x) -> System.out.println(x);
con.accept(message);
}
例如,遍历打印字符串列表中的元素:
List<String> list = Arrays.asList("苹果","桃子","西瓜","香蕉");
list.forEach( k->System.out.println(k) );
- 格式三:多参数Lambda表达式情形:多参数情形是指有二个以上参数的情况,其语法一般格式为:
([类名1] 变量名1,[类名2] 变量名2[,…])->{ 程序语句块 }
如果不能推断出类名时,要声明参数类型,然后用符号“->”指向语句块。例如:
(String str1,String str2)-> { 具体的语句 }
(String str1,String str2)-> str1.length() – str2.length()
通常情况下,编译器都可推断出参数的类名,类名可省略:
(变量名1,变量名2[,…])->{ 程序语句块 }
有多行程序语句时花括号不能省略。例如:(str1,str2)-> { 具体的语句块 }
下面是字符串数组排序的示例代码,只有一行代码省略花括号和语句结束符:
String[] array = { "Mary","Tony","John","Bob"};
Arrays.sort( array, (a,b)->a.compareTo(b) );
再来看一个例子,有两个参数,有返回值的:(x, y) -> x + y
public void test3() {
//用Lambda表达式给函数接口实例赋值
BinaryOperator<Integer> binary = (x, y) -> x + y;
System.out.println(binary.apply(1, 2)); // 3
}
- 语法四:Lambda表达式的返回类型无需指明,会根据上下文推导得到。如果Lambda表达式有返回值,则不能只实现部分的分支,这和普通方法的规则是相同的。
下面这个表达式不合法,因为只有x>=0的分枝,缺少x<0分支:
// 不正确的写法,只实现了部分分枝
( int x ) -> { if(x>=0)return true; }
正确的写法为: x-> return (x>=0) ? true : false
// 正确的写法
x-> return (x>=0) ? true : false
Lambda 表达式参数的数据类型通常可以省略,因为大多可由编译器推断得出,称为“类型推断”。
public void test5() {
//直接使用Lambda 表达式,“类型推断”
Integer sum = Arrays.asList(1, 3, 5, 2, 4).stream().reduce(0, (x, y) -> x + y);
System.out.println("sum = "+ sum); //打印“sum = 15”
}
可以看到,在Lambda 表达式中的参数列表,可以不用写参数的类型,称为“类型推断”。这与 java7中 new ArrayList<>(); 类似,<>棱形操作符不需要指定泛型类型,可根据上下文做类型的推断是一样道理。
- Lambda 表达式的特殊用法:方法引用
方法引用(method references),这种语法用来替代某些特殊形式Lambda表达式。如果Lambda表达式的全部内容就是调用一个已有的方法,那么可以用方法引用来替代Lambda表达式。方法引用可以细分为四类:
参考文档