学如逆水行舟,不进则退
JDK1.8中的lambda表达式到底实际工作中该怎么用啊?各种百度文章,不明所以,还是自己记录一下,留给自己做参考。
一、定义(源自百度百科)
Lambda 表达式(lambda expression)是一个匿名函数,是一种函数式编程思想,是Java面向对象编程思想的进阶。Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Java,C#,Pythod都有其对应的lambda表达式(源自百度百科)。
二、解释
还是有些不明白?知道算数表达式4*5=20,逻辑表达式a>b结果为true,那JDK1.8中的lambda表达式到底是个什么东西?都知道Java中可以对变量赋值People p=null,JDK1.8中的lambda表达式功能更强大了,可以将一段代码赋值给变量了,如下:
//仅示例,实际编译不通过
People p = public void eat(String food){
System.out.println("正在吃"+food);
};
将一些可以省略的东西进行省略——先省略public 关键字,其次是根据上面介绍的匿名函数的概念(重点是在于匿名),可以省略方法名eat;编译器可以自行推断返回类型void,这个可以进行省略;参数类型String,编译器也可推断;如果函数体中只有一行代码的话,也可以将花括号{}省略;最后将参数通过->传到函数体中,一个lambda表达式就这样形成了。
People p = (food)->System.out.println("正在吃"+food);
上述的People p只是示例,那么真正接收lambda表达式的变量是个什么类型?lambda表达式如何直白的总结?下面用熟知的Runnable接口来演示和解释:
public static void main(String[] args) {
//匿名内部类的方式创建线程
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
t1.start();
//lambda表达式的方式创建线程
Runnable r =()-> System.out.println(Thread.currentThread().getName());
Thread t = new Thread(r);
t.start();
}
在用lambda表达式创建线程的方式上,接收lambda表达式的是一个Runnable接口,其实这个Runnable是一个函数式接口(细讲)。通过与匿名函数创建线程的方式比对发现,个人片面的理解其实lambda表达式就是函数式接口的一种具体实现。
三、语法规则
(参数类型 参数名称, 参数类型 参数名称) ‐> { 表达体 }
规则一:无参无返回值
Runnable r =()-> System.out.println(Thread.currentThread().getName());
new Thread(r).start();
规则二:无参有返回值
lambda表达体只有一行语句时,可以省略return和花括号。
Supplier<String> supplier = ()->new String("中国万岁");
System.out.println(supplier.get());
规则三:有参无返回值
当有一个参数时,参数的小括号可以省略。
Consumer<String> con = x -> System.out.println(x);
con.accept("有参无返回值");
规则四:有参有返回值
有花括号存在,多条语句时,return不可省略。
Comparator<Integer> com = (x, y) -> {
System.out.println("函数式接口");
return Integer.compare(x, y);
};
System.out.println(com.compare(10, 8));
Lambda表达式精简总结:
*简化参数类型,参数类型可以不写。
*当有一个参数时,参数的小括号可以省略。
*当只有一行语句时,可以省略表达体中的return和花括号。
四、常用(待补充...)
1.遍历集合,不再使用for,foreach。
List<String> stringList = Arrays.asList("a", "ab", "abc");
stringList.forEach(x-> System.out.println(x));
2.对集合排序
package com.sinosoft.service.impl;
/**
* @Author: qw
* @Description: 学生类
* @Date: 2021/5/10 23:34
*/
public class Student {
private String name;
private int age;
public Student(String name,int age){
this.name=name;
this.age=age;
}
//............
@Override
public String toString() {
return name+":"+age;
}
}
public static void main(String[] args) {
//对集合排序
List<Integer> list = Arrays.asList(10, 5, 8);
Collections.sort(list, (x, y) -> Integer.compare(x,y));
list.forEach(x-> System.out.println(x));
Student stu1 = new Student("张三", 26);
Student stu2 = new Student("李四", 22);
Student stu3 = new Student("王五", 28);
List<Student> studentList = new ArrayList<>();
studentList.add(stu1);
studentList.add(stu2);
studentList.add(stu3);
Collections.sort(studentList, (s1, s2) ->Integer.compare(s1.getAge(),s2.getAge()));
studentList.forEach(x-> System.out.println(x.toString()));
}
3.结合函数式接口,比如常用的断言型函数式接口,可以封装过滤操作(通过某些业务条件,删选一个集合的数据到一个新的集合中)。
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
List<String> list1 = new ArrayList<>();
List<Integer> numbers = Arrays.asList(10, 5, 8);
List<String> strList = Arrays.asList("15588888888", "16788888888", "15888888888");
//扩展用法一:筛选偶数集合
filter(numbers,list,x ->(int)x % 2 == 0);
list.forEach(System.out::println);
//扩展用法二:筛选155开头的手机号
filter(strList,list1,s->String.valueOf(s).startsWith("155"));
list1.forEach(System.out::println);
//扩展用法n.....
}
public static void filter(List oldList, List newList,Predicate condition) {
oldList.forEach(x -> {
if (condition.test(x)) {
newList.add(x);
}
});
}
4.结合StreamAPI,完成更复杂的操作。
本文参考文章及资料
https://www.cnblogs.com/myseries/p/13873670.html
https://www.runoob.com/java/java8-functional-interfaces.html