Lambda表达式
一. 入门Lambda表达式
1.1 概述
- Lambda表达式是JDK8中的一个语法糖, 他可以对某些匿名内部类的写法进行化简. 它是函数式编程思想的一个重要体现. 它的本质就是: 不关注是什么对象, 而是关注我们对数据进行了什么操作.
1.2 核心原则:
-
参数类型的可推导 :
- 在许多编程语言支持的 Lambda 表达式中,参数类型是可以被推导出来的。以 Java 为例,当使用 Lambda 表达式实现一个函数式接口时,编译器可以根据函数式接口中抽象方法的参数类型来推断 Lambda 表达式中参数的类型。
- 这里编译器根据
Function<Integer, Integer>
接口的apply方法的参数类型知道x是Integer类型,不需要显式地写成(Integer x) -> x * x
。这种参数类型的推导机制使得代码更加简洁,尤其是在参数类型比较明显的情况下。可以写成(x) -> x * x;
的形式
-
参数括号的可省略(在特定情况下)
- 当 Lambda 表达式只有一个参数时,参数周围的括号可以省略。还是以 Java 为例,对于函数式接口Consumer(它有一个抽象方法accept,接受一个String参数且没有返回值),可以这样写 Lambda 表达式:
Consumer<String> printString = str -> System.out.println(str);
这里省略了参数str周围的括号。但是如果有多个参数,括号就不能省略,比如对于函数式接口BiFunction<Integer, Integer, Integer>(它有一个抽象方法apply,接受两个Integer参数并返回一个Integer),Lambda 表达式应该写成(x,y) -> x + y
。
-
花括号和 return 关键字的省略(在特定情况下)
- 当 Lambda 表达式的主体是一个简单的表达式(只包含一条语句),并且这条语句返回一个值时,花括号和return关键字可以省略。
1.3 基本格式:
- (参数列表) -> { 代码 }
- 参数列表: 用于接收输入值. 可以为空, 如
( ) ->{ }
表示没有参数; 可以有一个参数,如(x)->{ }
,在某些情况下,当只有一个参数时,括号可以省略,写成x->{}
;也可以有多个参数,如(x,y)->{}
… - 箭头符号(->): 这是 Lambda 表达式的语法标志,用于分隔参数列表和表达式主体,清晰地表明参数的输入和表达式主体对这些参数的操作。
- 表达式主体: 这是 Lambda 表达式的核心部分,它是对参数进行操作的代码。表达式主体可以是一个简单的表达式,如
(x+y)->x+y
,这种情况下,表达式的值就是 Lambda 表达式的返回值;也可以是一个代码块,用花括号{…}包裹,如(x,y)->{int z= x+y; return z}
,如果是代码块形式,需要使用语句来返回值(如果有返回值要求的话)
- 参数列表: 用于接收输入值. 可以为空, 如
二. 使用Lambda表达式
例一
- 使用匿名内部类的方式创建线程->转为Lambda表达式
- 代码展示:
public class Demo {
public static void main(String[] args) {
// 使用匿名内部类创建线程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("hello world");
}
});
thread.start();
// 使用lambda表达式创建线程
Thread thread1 = new Thread(() -> System.out.println("hello world"));
}
}
- 转换规则: 只保留匿名内部类的参数部分
()
和要执行的代码逻辑System.out.println("hello world");
例二
- 现有方法定义如下,其中IntBinaryOperator是一个接口。先使用匿名内部类的写法调用该方法。
- 匿名内部类写法:
public static int calculateNum(IntBinaryOperator operator){
int a = 10;
int b = 20;
return operator.applyAsInt(a, b);
}
public static void main(String[] args) {
int i = calculateNum(new IntBinaryOperator() {
@Override
public int applyAsInt(int left, int right) {
return left + right;
}
});
System.out.println(i);
}
- Lambda表达式写法:
public static void main(String[] args) {
int i = calculateNum((int left, int right)->{
return left + right;
});
System.out.println(i);
}
- 转换规则: 只保留匿名内部类的参数部分
(int left, int right)
和要执行的代码逻辑return left + right;
例三
- 现有方法定义如下,其中IntPredicate是一个接口。先使用匿名内部类的写法调用该方法。
- 匿名内部类写法:
public static void printNum(IntPredicate predicate){
int[] arr = {1,2,3,4,5,6,7,8,9,10};
for (int i : arr) {
if(predicate.test(i)){
System.out.println(i);
}
}
}
public static void main(String[] args) {
printNum(new IntPredicate() {
@Override
public boolean test(int value) {
return value%2==0;
}
});
}
- Lambda表达式写法:
public static void main(String[] args) {
printNum((int value)-> {
return value%2==0;
});
}
public static void printNum(IntPredicate predicate){
int[] arr = {1,2,3,4,5,6,7,8,9,10};
for (int i : arr) {
if(predicate.test(i)){
System.out.println(i);
}
}
}
- 转换规则: 只保留匿名内部类的参数部分
int value
和要执行的代码逻辑return value%2==0
’
例四
- 现有方法定义如下,其中Function是一个接口。先使用匿名内部类的写法调用该方法。
- 匿名内部类写法:
public static <R> R typeConver(Function<String,R> function){
String str = "1235";
R result = function.apply(str);
return result;
}
public static void main(String[] args) {
Integer result = typeConver(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.valueOf(s);
}
});
System.out.println(result);
}
- Lambda表达式写法:
Integer result = typeConver((String s)->{
return Integer.valueOf(s);
});
System.out.println(result);
- 转换规则: 只保留匿名内部类的参数部分
String s
和要执行的代码逻辑return Integer.valueOf(s);
例五
- 现有方法定义如下,其中IntConsumer是一个接口。先使用匿名内部类的写法调用该方法。
- 匿名内部类写法:
public static void foreachArr(IntConsumer consumer){
int[] arr = {1,2,3,4,5,6,7,8,9,10};
for (int i : arr) {
consumer.accept(i);
}
}
public static void main(String[] args) {
foreachArr(new IntConsumer() {
@Override
public void accept(int value) {
System.out.println(value);
}
});
}
- Lambda表达式写法:
public static void main(String[] args) {
foreachArr((int value)->{
System.out.println(value);
});
}
- 转换规则: 只保留匿名内部类的参数部分
(int value)
和要执行的代码逻辑System.out.println(value);
三.总结
- Lambda表达式如何书写: 只保留匿名内部类的参数部分->要执行的代码逻辑.
- Lambda表达式的省略规则:
- 参数类型可以省略
- 方法体只有一句代码时大括号return和唯一一句代码的分号可以省略
- 方法只有一个参数时小括号可以省略
- 以上这些规则都记不住也可以省略不记