关于Lambda表达式的详细用法
重点:别只看不动手,脑子明白了,手可不一定。
本文来自于B站博主:倜傥的雷哥 的视频讲解总结
视频链接: 视频链接
文章目录
1. Lambda表达式
Lambda表达式起初是为了取代匿名内部类的使用,写出更优雅的代码,尤其是在集合的遍历和操作中,可以极大的简化代码的结构。
Jdk也提供了大量的内置函数式接口供我们使用。
缺点:代码更加难懂。
匿名内部类,以线程为例(没有名字的内部类)
new Thread(new Runnable(){
public void run(){
}
}).start();
1.1 Lambda表达式对接口的要求
虽然lambda表达式可以对某些接口进行简单的实现,但是不是所有的接口都可以用lambda表达式来实现,
Lambda表达式规定接口中只能有一个需要被实现的方法,但不是规定接口中只能有一个方法。其他方法可以使用default进行默认的实现,进而不影响Lambda表达式的使用。
1.2 @FunctionalInterface注解
修饰函数式接口的,要求被修饰的接口抽象方法只能有一个,这个注解往往和lambda表达式一起使用。
/**
* Create with IntelliT IDEA
*
* @Author: zhengmingzhe
* @Date: 2022/07/30/16:35
* @Description: @FunctionalInterface注解用来验证此接口中有且只能有一个被实现的方法
*/
@FunctionalInterface
public interface MyInterface {
// 只加a方法注解不会报错 再加上b接方法就会报错 除非把b方法用default进行默认实现
// (注意被default修饰实现的方法得加上大括号方法体默认实现,抽象方法不用加方法体)
void a();
default void b() {
}
}
1.3 lambda表达式的基础语法
首先准备未使用Lambda表达式简写的接口 ,方便后续作对比~别偷懒 认真点看!
/**
* Create with IntelliT IDEA
*
* @Author: zhengmingzhe
* @Date: 2022/07/30/16:41
* @Description: 测试未使用lambda的接口
*/
public class LambdaInterface {
//无返回无参数
}
interface NoReturnNoParam{
void method();
}
//无返回有一个参数
@FunctionalInterface
interface NoReturnOneParam{
void method(int a);
}
//无返回有多个参数
@FunctionalInterface
interface NoReturnMultiParam{
void method(int a,int b);
}
//有返回无参数
@FunctionalInterface
interface ReturnNoParam{
int method();
}
//有返回有一个参数
@FunctionalInterface
interface ReturnOneParam{
int method(int a);
}
//有返回有多个参数
interface ReturnMultiParam{
int method(int a,int b);
}
真正强大的人能耐得住寂寞~认真看完!
1,重点如果方法体里面只有一句话可以直接省略去掉方法体。
2,参数类型也可以省略,即时是多个参数而且参数的类型不一样!
/**
* Create with IntelliT IDEA
*
* @Author: zhengmingzhe
* @Date: 2022/07/30/17:04
* @Description: 使用Lambda 语法简化6种接口的表达
*/
public class LambdaTest01 {
public static void main(String[] args) {
// 无参无返回(未使用Lambda表达式调用语法较麻烦)
NoReturnNoParam noReturnNoParam = new NoReturnNoParam() {
@Override
public void method() {
System.out.println("未使用Lambda表达式!");
System.out.println("未使用Lambda表达式!");
}
};
noReturnNoParam.method();
// 无参无返回 使用Lambda表达式简化
NoReturnNoParam noReturnNoParam0 = () -> {
System.out.println("未使用Lambda表达式!");
System.out.println("未使用Lambda表达式!");
};
noReturnNoParam0.method();
// 无参无返回 使用Lambda表达式再次简化(这样写的前提是方法体里只有一句话)
NoReturnNoParam noReturnNoParam1 = () -> System.out.println("未使用Lambda表达式!");
noReturnNoParam1.method();
// 一个参数无返回值 使用Lambda表达式简化(打印10)
NoReturnOneParam noReturnOneParam0 = (int a) -> System.out.println(a);
noReturnOneParam0.method(10);
//一个参数无返回值 使用Lambda表达式简化 也可以省略参数类型(打印12)
NoReturnOneParam noReturnOneParam1 = (a) -> System.out.println(a);
noReturnOneParam1.method(12);
// 多个参数无返回值(输出1和2)
NoReturnMultiParam noReturnMultiParam = (int a, int b) ->
{
System.out.println(a);
System.out.println(b);
};
noReturnMultiParam.method(1, 2);
//无参数有返回值 此时如果只有一条语句就可以去掉大括号(两种写法都是打印返回值110)
ReturnNoParam returnNoParam0 = () -> {
return 110;
};
ReturnNoParam returnNoParam1 = () -> 110;
System.out.println(returnNoParam0.method());
System.out.println(returnNoParam1.method());
// 一个参数有返回值(输出6)
ReturnOneParam returnOneParam = (a) -> a;
System.out.println(returnOneParam.method(6));
//多个参数有返回值(输出30)
ReturnMultiParam returnMultiParam =(int a,int b)->a+b;
System.out.println(returnMultiParam.method(10,20));
}
}
2.方法引用
- 如果一个类中的实现方法,其参数列表和返回值类型与某个函数式接口中的方法一致,那么可以使用方法引用的方式来代替Lambda表达式
- Java编译器会利用函数式接口中的方法的参数来调用引用的方法,并将该方法的返回值(如果有的话)作为接口方法的返回值
- 方法引用使用操作符::将对象或者类的名字与方法名隔开。
Java中的方法引用有六种形式,可以根据情况选择使用:
-
静态方法引用:
Class::staticMethodName
。引用静态方法,例如:Math::max
。 -
实例方法引用:
object::instanceMethodName
,引用特定对象的实例方法。Class::instanceMethodName
,引用抽象类型的实例方法。
-
特定类的任意对象的方法引用:
Class::instanceMethodName
,引用特定类型的任意对象的实例方法。 -
构造方法引用:
Class::new
,引用构造函数。例如:ArrayList::new
。 -
数组构造方法引用:
Type[]::new
,引用数组构造函数。例如:int[]::new
。 -
超类的实例方法引用:
super::instanceMethodName
,引用超类的实例方法。
这些方法引用可根据上下文更清晰地表示Lambda表达式的操作,并且可以提高代码的可读性和简洁性。根据情况,选取合适的方法引用可以让代码更加简洁易懂。
Lambda 表达式方法引用格式如下:(结合例子看)
1,静态方法
接口 对象名 =类名::静态方法名;
2,实例方法
接口 对象名 = 对象::实例方法名;
BiFunction<类名, Integer, Integer> 对象名 = 类名::实例方法名;
3,成员方法
(实例方法属于成员方法 ,实例方法是未使用static修饰的方法,成员方法是类中声明的方法)
接口 对象名 = new 类名.成员方法名;
package com.zmz.lambda;
import java.util.function.BiFunction;
import java.util.function.ToIntBiFunction;
/**
* Create with IntelliT IDEA
*
* @Author: zhengmingzhe
* @Date: 2022/07/30/18:03
* @Description: Lambda表达式简化的写法(实现接口调用类的方法)
*/
public class Lambda02 {
/*
* @Description 这是一个静态方法
* @Param
* @return
**/
public static int num(int n){
return n+100;
}
/*
* @Description 这是一个成员方法,也是一个实例方法
* @Param
* @return
**/
public int row(int a){
return a+200;
}
public static void main(String[] args){
//静态方法使用----------------------------------------
//使用有一个参数,并带返回值(输出结果是20)
ReturnOneParam returnOneParam = (a)-> a+10;
System.out.println(returnOneParam.method(10));
//使用有一个参数,并带返回值(输出结果是120) 调用本类静态方法直接调用
ReturnOneParam returnOneParam0 = (a)->num(a);
System.out.println(returnOneParam0.method(20));
//使用有一个参数,并带返回值(输出结果是120) 调用某个类的静态方法格式如下 不需要箭头(此格式只支持方法不支持成员属性)
ReturnOneParam returnOneParam1 = Lambda02::num;
System.out.println(returnOneParam1.method(20));
//成员方法使用------------------------------------------
//使用有一个参数,并带返回值(输出结果是202)调用其他类或者本类的成员方法的另一种写法(其实就是实现了接口里的抽象方法)
ReturnOneParam returnOneParam2 = (int b)->{
return new Lambda02().row(b);};
System.out.println(returnOneParam2.method( 2));
//实例方法使用--------------------------------------------------
//使用有一个参数,并带返回值(输出结果是201)因为row方法也属于实例方法 ,也可以用 对象::实例方法 方式调用
Lambda02 lambda = new Lambda02();
ReturnOneParam returnOneParam3 = lambda::row;
System.out.println(returnOneParam2.method(1));
//使用有一个参数,并带返回值(输出结果是202)因为row方法也属于实例方法 ,也可以用 类名::实例方法 方式调用(目前测试该实例方法只允许一个参数一个返回值,如果多个参数可采用成员方法的方式调用)
// 第一个参数是类名 第二个参数是传入的值 第三个参数是返回值
/*
public interface BiFunction<T, U, R> {
R apply(T t, U u);
*/
BiFunction<Lambda02, Integer, Integer> row = Lambda02::row;
System.out.println(returnOneParam2.method(2));
}
}
4.构造方法
/**
* Create with IntelliT IDEA
*
* @Author: zhengmingzhe
* @Date: 2022/07/30/18:41
* @Description: lambda 实现接口调用类的构造方法
*/
class Item {
int id;
String name;
double price;
public Item(int id,String name,double price){
this.id=id;
this.name=name;
this.price=price;
}
public Item(){
}
}
public class Lambda03 {
public static void main(String[] args) {
//使用无参的构造方法来引用 输出对象com.zmz.lambda.Item@404b9385
ItemCreatorBlankConstruct construct = () -> new Item();
Item item1 = construct.getItem();
System.out.println(item1);
//使用无参的构造方法来引用 输出对象com.zmz.lambda.Item@404b9385
ItemCreatorBlankConstruct construct2 =Item::new;
Item item2 = construct2.getItem();
System.out.println(item2);
//使用有参构造方法来引用 输出对象com.zmz.lambda.Item@404b9385
ItemCreatorParamConstruct construct3 =Item::new;
Item item3 = construct3.getItem(1,"手机",9999);
System.out.println(item3);
}
}
interface ItemCreatorBlankConstruct {
Item getItem();
}
interface ItemCreatorParamConstruct {
Item getItem(int id, String name, double price);
}
5.Stream.map()中的引用(在后续的Stream流中会经常用到)
List<DocumentFile> fileList =new ArrayList<>();
//取出fileList中的fileUrl字段值再重新规约成一个集合
List<String> objectNames = fileList.stream().map(documentFile -> documentFile.getFileUrl()).collect(Collectors.toList());
//由于 Func1<DocumentFile, String> getFileUrls = DocumentFile::getFileUrl; Func1的第一个参数是参数类型第二个是返回值类型,源码如下
/**
public interface Func1<P, R> extends Serializable {
R call(P parameter) throws Exception;
*/
//所以上面的.map的表达式等价于下面的
List<String> objectNames = fileList.stream().map(documentFile::getFileUrl).collect(Collectors.toList());
//或者以成员方法的方式考虑,类名::成员方法名
3,lambda表达式创建线程
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Create with IntelliT IDEA
*
* @Author: zhengmingzhe
* @Date: 2022/07/30/19:04
* @Description: Lambda 表达式创建线程对象
*/
public class Lambda04 {
public static void mian(String [] args){
// Runnable执行run方法无返回值 Callable执行call方法有返回值
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("创建线程");
}
}).start();
//使用lambda表达式简化 因为上面的run没有参数没有返回值 new Runnable()可写为()->{}
new Thread(
()->System.out.println("使用Lambda创建线程")
).start();
ExecutorService executorService = Executors.newCachedThreadPool();
//Runnable
executorService.submit(()->{
System.out.println("提交Runnable");
});
//Callable
executorService.submit(()->{
System.out.println("提交Callable");
return "a";
});
}
}
4.遍历简单集合
/**
* Create with IntelliT IDEA
*
* @Author: zhengmingzhe
* @Date: 2022/07/30/19:22
* @Description: 使用Lambda表达式遍历简单集合
*/
public class Lmbda05 {
public static void main (String[] args){
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
// List<Integer> list2 =new ArrayList<>();
// list2.add(1);
// list2.add(2);
// list2.add(3);
// list2.add(4);
// list2.add(5);
//第一种for循环遍历
for(Integer integer: list){
System.out.println(integer+"\t");
}
//i++循环遍历
for(int i=0 ;i<list.size();i++){
System.out.println(list.get(i)+"\t");
}
//lambda表达式遍历 先看forEach源码其实就是个增强for 往forEach里面传入了一个接口参数Consumer
// Consumer里面的方法有一个参数 无返回值
// default void forEach(Consumer<? super T> action) {
// Objects.requireNonNull(action);
// for (T t : this) {
// action.accept(t);
// }
// }
// @FunctionalInterface
// public interface Consumer<T> {
//
// void accept(T t);
// }
list.forEach((t)->{
System.out.println(t);
});
//进一步优化
list.forEach(System.out::println);
}
}
5,遍历复杂集合
/**
* Create with IntelliT IDEA
*
* @Author: zhengmingzhe
* @Date: 2022/07/30/19:43
* @Description: 构建一个实体类
*/
public class Item2 {
int id;
String name;
double price;
Item2(){
}
Item2(int id ,String name,double price){
this.id= id;
this.name =name;
this.price =price;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Item2{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
'}';
}
}
/**
* Create with IntelliT IDEA
*
* @Author: zhengmingzhe
* @Date: 2022/07/30/19:47
* @Description: 用lambda表达式遍历复杂集合
*/
public class Lambda06 {
public static void main(String [] args){
List<Item2> list = new ArrayList<>();
list.add(new Item2(1,"阿萨",12.22));
list.add(new Item2(2,"撒旦",12.21));
list.add(new Item2(3,"答案",11.22));
//以前的遍历方法
for(int i =0 ;i<list.size() ;i++){
System.out.println(list.get(i).id);
}
for(Item2 item2 :list){
System.out.println(item2.getName());
}
list.forEach(i->System.out.println(i.getPrice()));
list.forEach(System.out::println);
}
}
6,集合元素删除
package com.zmz.lambda;
import java.util.ArrayList;
import java.util.List;
/**
* Create with IntelliT IDEA
*
* @Author: zhengmingzhe
* @Date: 2022/07/30/19:57
* @Description: 用lambda表达式删除集合
*/
public class Lambda07 {
public static void main(String [] args) {
List<Item2> list = new ArrayList<>();
list.add(new Item2(1, "阿萨", 12.22));
list.add(new Item2(2, "撒旦", 12.21));
list.add(new Item2(3, "答案", 11.22));
//以前的方法 删除id=3的元素
for(Item2 item2:list){
if(item2.id==3){
list.remove(item2);
break;
}
}
list.forEach(t->System.out.println(t));
//使用lambda移除id=3的元素
list.removeIf(t->{
return t.getId() ==3;
});
list.forEach(t->System.out.println(t));
list.removeIf(t-> t.getId() ==3);
list.forEach(t->System.out.println(t));
}
}
7,集合排序
/**
* Create with IntelliT IDEA
*
* @Author: zhengmingzhe
* @Date: 2022/07/30/20:17
* @Description: 使用lambda进行集合排序
*/
public class Lambda08 {
public static void main(String [] args) {
List<Item2> list = new ArrayList<>();
list.add(new Item2(1, "阿萨", 10.22));
list.add(new Item2(2, "撒旦", 20.21));
list.add(new Item2(3, "答案", 22.22));
// Collections.sort(list, new Comparator<Item2>() {
// @Override
// public int compare(Item2 o1, Item2 o2) {
// return (int)(o1.getPrice()-o2.getPrice());
// }
// });
list.forEach(t->System.out.println(t));
Collections.sort(list,(a,b)->(int)(a.getPrice()-b.getPrice()));
list.forEach(t->System.out.println(t));
}
}
ps:一定要多学多练 ,语法知识只能熟能生巧L
下一篇文章有我对Stream流的详细介绍:
博客链接:Stream流的详细用法介绍