Java 8新特性(2) Lambda 表达式
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
使用 Lambda 表达式可以使代码变的更加简洁紧凑。
Lambda语法
(parameters) -> expression
或
(parameters) ->{ statements; }
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
Lambda 表达式实例
// 1. 不需要参数,返回值为 5
() -> 5
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
// 4. 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
完整的例子
public class TestLambda {
public static void runThreadUseLambda() {
//Runnable 是一个函数接口,只包含了有个无参数的,返回 void 的 run 方法;
//所以 lambda 表达式左边没有参数,右边也没有 return,只是单纯的打印一句话
new Thread(() ->System.out.println("lambda实现的线程")).start();
}
public static void runThreadUseInnerClass() {
//这种方式就不多讲了,以前旧版本比较常见的做法
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("内部类实现的线程");
}
}).start();
}
public static void main(String[] args) {
TestLambda.runThreadUseLambda();
TestLambda.runThreadUseInnerClass();
}
}
方法和构造函数引用(::)
有时候 Lambda 表达式的代码就只是一个简单的方法调用而已,遇到这种情况,Lambda 表达式还可以进一步简化为方法引用(Method References)。一共有四种形式的方法引用:
引用静态方法
List<Integer> ints = Arrays.asList(3, 7, 2); // [3, 7, 2]
// ints.sort((a,b) -> Integer.compare(a,b)); // [2, 3, 7]
ints.sort(Integer::compare); // [2, 3, 7]
引用特定对象的实例方法(单个对象的)
List<Integer> ints = Arrays.asList(3, 7, 2);
// ints.forEach(x -> System.out.print(x));
ints.forEach(System.out::print);
/** output:
372
*/
@FunctionalInterface
interface Converter<F, T> {
T convert(F from);
}
class Something {
String startsWith(String s) {
return String.valueOf(s.charAt(0));
}
}
Something something = new Something();
Converter<String, String> converter = something::startsWith;
String converted = converter.convert("Java");
System.out.println(converted); // "J"
对特定类型的任意对象
的实例方法的引用
String[] stringArray = {"Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda"};
Arrays.sort(stringArray, String::compareToIgnoreCase);
// Arrays.sort(stringArray, (a,b) -> a.compareToIgnoreCase(b));
System.out.println(Arrays.toString(stringArray));
构造函数
首先我们定义一个示例 bean,包含不同的构造方法:
class Person {
String firstName;
String lastName;
Person() {}
Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
接下来,我们定义一个 person 工厂接口,用来创建新的 person 对象:
interface PersonFactory<P extends Person> {
P create(String firstName, String lastName);
}
然后我们通过构造函数引用来把所有东西拼到一起,而不是像以前一样,通过手动实现一个工厂来这么做。
// PersonFactory<Person> personFactory = (a,b) -> new Person(a,b);
PersonFactory<Person> personFactory = Person::new;
Person person = personFactory.create("Peter", "Parker");
我们通过 Person::new
来创建一个 Person 类构造函数的引用。Java 编译器会自动地选择合适的构造函数来匹配 PersonFactory.create 函数的签名,并选择正确的构造函数形式。
Lambda 的范围
对于 lambdab 表达式外部的变量,其访问权限的粒度与匿名对象的方式非常类似。你能够访问局部对应的外部区域的局部 final 变量,以及成员变量和静态变量。
访问局部变量
我们可以访问 lambda 表达式外部的 final 局部变量:
final int num = 1; // final 不是必须的
Converter<Integer, String> stringConverter =
(from) -> String.valueOf(from + num);
stringConverter.convert(2); // 3
num = 3; // 编译失败,即使 num 没有声明 final,也是 final 的,无法改变
访问成员变量和静态变量
与局部变量不同,我们在 lambda 表达式的内部能获取到对成员变量或静态变量的读写权。这种访问行为在匿名对象里是非常典型的。
class Lambda4 {
static int outerStaticNum;
int outerNum;
void testScopes() {
Converter<Integer, String> stringConverter1 = (from) -> {
outerNum = 23;
return String.valueOf(from);
};
Converter<Integer, String> stringConverter2 = (from) -> {
outerStaticNum = 72;
return String.valueOf(from);
};
}
}
访问默认接口方法
interface Formula {
double calculate(int a);
default double sqrt(int a) {
return Math.sqrt(a);
}
}
Formula formula = new Formula() { // 默认方法可以在匿名对象中使用
@Override
public double calculate(int a) {
return sqrt(a * 100);
}
};
formula.calculate(100); // 100.0
formula.sqrt(16); // 4.0
默认方法无法在lambda表达式内部被访问。因此下面的代码是无法通过编译的:
Formula formula = (a) -> sqrt( a * 100);
参考
https://blog.csdn.net/zxhoo/article/details/38349011
https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
http://www.runoob.com/java/java8-lambda-expressions.html
https://wizardforcel.gitbooks.io/modern-java/content/ch1.html
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 bin07280@qq.com
文章标题:Java 8新特性(2) Lambda 表达式
文章字数:1.3k
本文作者:Bin
发布时间:2019-03-13, 21:07:22
最后更新:2019-08-06, 00:07:35
原始链接:http://coolview.github.io/2019/03/13/Java8/Java%208%E6%96%B0%E7%89%B9%E6%80%A7(2)%20Lambda%20%E8%A1%A8%E8%BE%BE%E5%BC%8F/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。