Lambda表达式介绍
Lambda表达式是一个匿名函数(方法)代码块,可以作为表达式、方法参数和方法返回值。
Lambda表达式标准语法形式如下:
(参数列表) -> {
//Lambda表达式
}
Lambda表达式实现的接口不是普通的接口,称为函数式接口,这种接口只能有一个方法。如果接口中声明多个抽象方法,那么Lambda表达式会发生编译错误。
@FunctionalInterface 声明函数式接口注解
在接口前使用@FunctionalInterface注解修饰,那么试图增加一个抽象方法时会发生编译错误。但是可以添加默认方法和静态方法。
1、Lambda表达式简化形式
1)省略参数类型
Lambda表达式可以根据上下文环境推断出参数类型。
public class HelloWorld {
public static void main(String[] args) {
int n1 = 10;
int n2 = 5;
// 实现加法计算Calculable对象
Calculable f1 = calculate('+');
// 实现减法计算Calculable对象
Calculable f2 = calculate('-');
// 调用calculateInt方法进行加法计算
System.out.printf("%d + %d = %d \n", n1, n2, f1.calculateInt(n1, n2));
// 调用calculateInt方法进行减法计算
System.out.printf("%d - %d = %d \n", n1, n2, f2.calculateInt(n1, n2));
}
/**
* 通过操作符,进行计算
* @param opr 操作符
* @return 实现Calculable接口对象
*/
public static Calculable calculate(char opr) {
Calculable result;
if (opr == '+') {
// Lambda表达式实现Calculable接口
result = (a, b) -> {
return a + b;
};
} else {
// Lambda表达式实现Calculable接口
result = (a, b) -> {
return a - b;
};
}
return result;
}
}
2)省略参数小括号
Lambda表达式有一个参数时,可以省略参数小括号。
public class HelloWorld {
public static void main(String[] args) {
int n1 = 10;
// 实现二次方计算Calculable对象
Calculable f1 = calculate(2);
// 实现三次方计算Calculable对象
Calculable f2 = calculate(3);
// 调用calculateInt方法进行加法计算
System.out.printf("%d二次方 = %d \n", n1, f1.calculateInt(n1));
// 调用calculateInt方法进行减法计算
System.out.printf("%d三次方 = %d \n", n1, f2.calculateInt(n1));
}
/**
* 通过幂计算
* @param power 幂
* @return 实现Calculable接口对象
*/
public static Calculable calculate(int power) {
Calculable result;
if (power == 2) {
// Lambda表达式实现Calculable接口
result = (int a) -> { //标准形式
return a * a;
};
} else {
// Lambda表达式实现Calculable接口
result = a -> { //省略形式
return a * a * a;
};
}
return result;
}
}
3)省略return和大括号
如果Lambda表达式体中只有一条语句,可以省略return和大括号
result = a -> a * a * a;
2、作为参数使用Lambda表达式
作为参数传递给方法是Lambda表达式的一个常见的用法。
public class HelloWorld {
public static void main(String[] args) {
int n1 = 10;
int n2 = 5;
// 打印计算结果加法计算结果
display((a, b) -> {
return a + b;
}, n1, n2); //1
// 打印计算结果减法计算结果
display((a, b) -> a - b, n1, n2); ///2
}
/**
* 打印计算结果
*
* @param calc Lambda表达式
* @param n1 操作数1
* @param n2 操作数2
*/
public static void display(Calculable calc, int n1, int n2) {//3
System.out.println(calc.calculateInt(n1, n2));
}
}
代码中第3行定义display打印计算方法,其中参数clac是Calculable,这个参数既可以接收实现Calculable接口的对象,也可以接收Lambda表达式,因为Calculable是函数式接口。
//可计算接口
@FunctionalInterface
public interface Calculable {
// 计算两个int数值
int calculateInt(int a, int b);
}
3、访问变量
Lambda表达式可以访问所在外层作用域内定义的变量,包括成员变量和局部变量。
public class LambdaDemo {
// 实例成员变量
private int value = 10;
// 静态成员变量
private static int staticValue = 5;
// 静态方法,进行加法运算 静态方法中不可以访问实例成员变量,也不能访问实例成员方法
public static Calculable add() {
Calculable result = (int a, int b) -> {
// 访问静态成员变量,不能访问实例成员变量
staticValue++;
int c = a + b + staticValue; // this.value;
return c;
};
return result;
}
// 实例方法,进行减法运算 实例方法中可以访问实例成员变量,也可以访问实例成员方法
// 当访问实例成员变量或者成员实例方法可以使用this,在不与局部变量发生冲突的情况下可以省略this
public Calculable sub() {
Calculable result = (int a, int b) -> {
// 访问静态成员变量和实例成员变量
staticValue++;
this.value++;
int c = a - b - staticValue - this.value;
return c;
};
return result;
}
}
捕获局部变量
对于成员变量的访问,Lambda表达式和普通方法没有区别,但是在访问外层局部变量时会发生“捕获变量”情况。在Lambda表达式中捕获变量时,会将变量当成final的,在Lambda表达式中不能修改那些捕获的变量。
// 静态方法,进行加法运算
public static Calculable add() {
//局部变量
int localValue = 20;
Calculable result = (int a, int b) -> {
// localValue++; //编译错误
int c = a + b + localValue;
return c;
};
return result;
}
4、方法引用
java8之后增加了“::”运算符,用于方法引用,不是调用方法。
方法引用分为静态方法的引用和实例方法的引用。
类型名::静态方法
实例名::实例方法
被引用方法的参数列表和返回值类型必须和函数式接口方法参数列表和方法返回值类型一致。
public class LambdaDemo {
// 静态方法,进行加法运算
// 参数列表要与函数式接口方法calculateInt(int a, int b)兼容
public static int add(int a, int b) {
return a + b;
}
// 实例方法,进行减法运算
// 参数列表要与函数式接口方法calculateInt(int a, int b)兼容
public int sub(int a, int b) {
return a - b;
}
}
public class HelloWorld {
public static void main(String[] args) {
int n1 = 10;
int n2 = 5;
// 打印计算结果加法计算结果
display(LambdaDemo::add, n1, n2); //display才是真正调用方法
LambdaDemo d = new LambdaDemo();
// 打印计算结果减法计算结果
display(d::sub, n1, n2);
}
/**
* 打印计算结果
* @param calc Lambda表达式
* @param n1 操作数1
* @param n2 操作数2
*/
public static void display(Calculable calc, int n1, int n2) {
System.out.println(calc.calculateInt(n1, n2));
}
}
来源:关东升 《Java从小白到大牛》