Lambda 表达式是一种匿名函数(对 Java 而言这并不完全正确,但现在姑且这么认为),简单地说,它是没有声明的方法,也即没有访问修饰符、返回值声明和名字。
你可以将其想做一种速记,在你需要使用某个方法的地方写上它。当某个方法只使用一次,而且定义很简短,使用这种速记替代之尤其有效,这样,你就不必在类中费力写声明与方法了。
java中的Lambda表达式通常使用(argument)->(body)语法书写,例如以下的:
(arg1, arg2...) -> { body }
(type1 arg1, type2 arg2...) -> { body }
这些是个例子:
(int a, int b) -> { return a + b; }
() -> System.out.println("Hello World");
(String s) -> { System.out.println(s); }
() -> 42
() -> { return 3.1415 };
Lamba表达式的结构:
- 一个 Lambda 表达式可以有零个或多个参数
- 参数的类型既可以明确声明,也可以根据上下文来推断。例如:
(int a)
与(a)
效果相同 - 所有参数需包含在圆括号内,参数之间用逗号相隔。例如:
(a, b)
或(int a, int b)
或(String a, int b, float c)
- 空圆括号代表参数集为空。例如:
() -> 42
- 当只有一个参数,且其类型可推导时,圆括号()可省略。例如:
a -> return a*a
- Lambda 表达式的主体可包含零条或多条语句
- 如果 Lambda 表达式的主体只有一条语句,花括号{}可省略。匿名函数的返回类型与该主体表达式一致
- 如果 Lambda 表达式的主体包含一条以上语句,则表达式必须包含在花括号{}中(形成代码块)。匿名函数的返回类型与代码块的返回类型一致,若没有返回则为空
函数式接口
在java中,Marker(标记)类型的接口就是所谓的函数式的接口就是一种没有方法或者是属性声明的接口。函数式接口只是包含一个抽象的方法声明的接口。
java中,java.lang.Runnable就是函数式接口,只是声明了一个方法void run()。需要使用匿名内部类的方式来进行实例化函数式接口。
此时有了Lambda表达式,这个方式可以很快的得到简化。
Runnable r = () -> System.out.println("hello world");
不指明函数式接口的时候,编译器就会自动的解释这种变化。
new Thread(
() -> System.out.println("hello world")
).start();
因此,编译器会进行自动的推断,根据线程类的构造函数为public Thread(Runnable r){ },将Lambda表达式赋值给Runnable接口。
Lambda表达式学习的例子,通过例子来学习相应的:
线程的初始化,可以使用Lambda的方式进行表达:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello from thread");
}
}).start();
//我们可以更改为这个样子的
new Thread(()-> {
System.out.println("hello from thread");
}
).start();
Lambda表达式与匿名内部类的区别:
匿名内部类和Lambda的区别在:
一、关键词的使用:
对于匿名内部类:关键词this解读为匿名类。
对于Lambda,关键词则解读为就Lambda的外部类。
二、两者的编译方法不同:
java编译器将Lambda表达式转化为类里面的私有函数,没有一个单独的.class字节码文 件,对应的字节码会在运行的时候动态生成。
匿名内部类:则是编译后生成一个单独的.class字节码文件。
三、所需的类型不同:
匿名内部类可以是接口,可以是抽象类,可以是具体类;
Lambda则只能够是接口。
四、使用的限制不同:
接口中有且仅有一个抽象方法,可以使用Lambda表达式,可以使用匿名内部类。
接口中多于一个抽象方法,只能够使用匿名内部类,不能够使用Lambda表达式。