lambda表达式用法超详细介绍(一篇文章足以学会lambda)

关于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中的方法引用有六种形式,可以根据情况选择使用:

  1. 静态方法引用: Class::staticMethodName。引用静态方法,例如:Math::max

  2. 实例方法引用:

    • object::instanceMethodName,引用特定对象的实例方法。
    • Class::instanceMethodName,引用抽象类型的实例方法。
  3. 特定类的任意对象的方法引用: Class::instanceMethodName,引用特定类型的任意对象的实例方法。

  4. 构造方法引用: Class::new,引用构造函数。例如:ArrayList::new

  5. 数组构造方法引用: Type[]::new,引用数组构造函数。例如:int[]::new

  6. 超类的实例方法引用: 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流的详细用法介绍

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

厌世小晨宇yu.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值