Lambda表达式

首先明确一点:Lambda表达式是由匿名内部类传参简化而来

使用lambda表达式的场景:

函数式接口做方法参数传递

(只要是想new一个函数式接口,就能用lambda,只是用的时候大多出现在传递参数的时候)

什么是函数式接口 ——> 一个接口有且仅有一个重写方法 可以用过在接口上加上@FunctionalInterface注解来判断

举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Test {
public static void main(String [] args){
new Thread(
new Runnable(){
@Override
public void run {
System.out.println("a new thread");
}
}
).start();
}
}

//在这个例子里,new Thread传入的参数是一个runnable的实现类对象(匿名内部类),而runnable接口本质上是一个函数式接口,它里面有且只有一个run方法需要重写,所以可以改成lambda表达式:

public class TestLambda{
public static void main(String []args){
new Thread(
()->{System.out.println("a new thread made by lambda");}
).start();
}
}
  • ()内是方法的参数,参数的类型可以省略,参数本身不能省略,当有且只有一个参数的时候,小括号可以省略
  • {}内是重写的方法体,只有一行的时候,可以省略大括号,只有一行return的时候,可以省略return关键字

几种常见的函数式接口:

Supplier 供应者,不接受数据,返回数据,重写get方法

Consumer 消费者,接受数据,不返回数据,重写accept方法

Function 函数式接口,接受数据,返回数据,重写apply方法

Predicate 断言接口,接收数据,返回真假,重写test方法

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public static void main(String []args){

testSupplier(
()->"rjctx" //返回数据
);

testConsumer(
s -> System.out.println(s + "ctx"); //消费数据
);

testFunction(
s ->{
if(s.equals("rjctx")){
return true;
}else{
return false;
}
}
);

testPredicate(
s -> {
if(s.equals("rjctx")){
return true;
}else{
return false;
}
}
);
}


public void testSupplier(Supplier<String> sp){
String result = sp.get();
}

public void testConsumer(Consumer<String> cm){
cm.accept("rj");
}

public void testFunction(Function<String,boolean> func){
Boolean boolean = func.apply("rjctx");
}

public void testPredicate(Predicate<String> pd){
Boolean boolean = pd.test("rjctx");
}

总的来说,函数式编程思想和面向对象不同

面向对象思想中,我们会往函数中传递确定的参数,让函数拿到这个参数去自己做一些操作

而在函数式编程思想中,给函数传递的参数变成了函数式接口,这意味着我们不再想传递确定的对象,然函数自己拿去使用,

而是想传递一个“函数模板”,给这个函数预留出一些其他的操作空间,在调用它的时候,给他传进去一些操作,

这样这个函数在不同场景下就能传递不同的模板内容实现不同的功能

Stream流

两种获取方法:

  • stream.of,以数组形式获取
  • 集合的实现类.stream(),以集合的方式获取

方法:

image-20251029124829230

终结方法:forEach和count

方法引用

什么时候用方法引用 ——> 当重写方法中,调用了一个新的方法,并且这个方法的参数,返回值都和重写方法相同时

更准确的说法:

方法引用的使用时机:当 Lambda 表达式的整个实现只是简单地调用一个已有的方法时,可以用方法引用替换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//这个lambda:
Consumer<String> consumer = s -> System.out.println(s);

//可以换成:
Consumer<String> consumer = System.out::println;




//MyBatisPlus中的方法引用:
// 传统方式 - 字符串字段名(容易出错)
QueryWrapper<User> wrapper1 = new QueryWrapper<>();
wrapper1.eq("name", "张三")
.gt("age", 18)
.select("id", "name", "email");

// MP方法引用方式 - 类型安全
QueryWrapper<User> wrapper2 = new QueryWrapper<>();
wrapper2.eq(User::getName, "张三") // 方法引用
.gt(User::getAge, 18) // 编译时检查
.select(User::getId, User::getName, User::getEmail);


//原理:
// MP 核心接口定义
@FunctionalInterface
public interface SFunction<T, R> extends Function<T, R>, Serializable {
}

// 实际使用的方法引用类型
SFunction<User, String> getNameRef = User::getName;