写点什么

【函数式编程实战】(三)Lambda 表达式原理与函数式接口精讲

  • 2022 年 7 月 22 日
  • 本文字数:1883 字

    阅读完需:约 6 分钟

前言:

📫 作者简介:小明 java 问道之路,专注于研究计算机底层,就职于金融公司后端高级工程师,擅长交易领域的高安全/可用/并发/性能的设计和架构📫

🏆 Java 领域新星创作者、阿里云专家博主、华为云享专家🏆

🔥 如果此文还不错的话,还请👍关注点赞收藏三连支持👍一下博主哦

本文导读

​本文先通过语法讲解-》引出函数式接口-》Lambda 原理解析-》函数式接口精讲,逐步深入

一、Lambda 表达式语法精讲 lambda 是什么?

我们通过前面两篇文章,了解 lambda 表达式可以理解为一种简洁可传递的匿名函数,没有名称只有->,有参数列表函数的大括号{}(函数主体),还可以有返回值,可传递理解为可以作为参数传递给方法或存储在变量中。

如图是使用 lambda 表达式,排序代码的语法解析

Lambda 表达式是不能直接使用 System.out.println 打印的 ,可以看到报了 “参数不匹配; *** 不是函数接口”,那什么是函数式接口?

二、函数式接口

函数式接口简单来说就是,只有一个抽象(abstract)方法的接口( interface),注如果我们只有一个抽象接口,但是有多个默认实现的方法,拿还是函数式接口

用函数式接口我们能做什么?Lambda 表达式 说是类似匿名内部类,所以提供的这个抽象方法是作为函数式接口的实例的,可以理解为,Lambda 表达式是 函数式接口的一个实现。

    run0(() -> {        System.out.println("执行run()内部逻辑");    });
// 由于Runnable中只定义了一个 抽象的 run() 方法,所以run方法就是一个函数式接口 void run0(Runnable r) { r.run(); }
复制代码

这段代码很好的诠释了,什么是函数式接口,函数式接口怎么用 lambda 实现。

三、Lambda 表达式原理解析

上面代码经过编译后, .class 中共有三个方法,一个默认构造方法,一个 main 方法,还多了一个我们没有定义过的方法: lambda0()显然,这个方法就是 lambda 表达式内逻辑操作方法,它是一个 static 的方法。那么,这个 lambda0()方法是怎么被调用的呢?

我们通过对 java 命令指定选项查看底层详细的编译过程:Java 在编译时,首先,在实现类的内部,将 Lambda 表达式,抽取出来作为一个 static 方法 lambda0();,然后对 Lambda.class(final 类)做了默认实现 $1.class,接下来,执行实现类的 main()方法时,就会对 lambda 表达式利用实现类中的 print()方法运行,最后将结果返回并打印。这就是 Lambda 表达式的底层运行逻辑。如图是上述代码的 .class 文件

四、函数式接口详解

就 Runnable 来说,JavaAPI 中实际上给我们提供了很多 函数式接口(例如 Runnable、Callable、Comparator),只不过我们很少提及这个概念,Java8 及后面高版本中有很多新的函数式接口,例如 Consumer、Function 、Predicate

Predicate:提供了一个 test 的抽象方法,如果你的 lambda 表达式,是想返回一个 boolean,那可以用这个方法接收 

代码实例如下:

Predicate<OrderInfo> non = orderInfo -> orderInfo.getOrderAmt().compareTo(BigDecimal.valueOf(100)) > 0;
for (OrderInfo orderInfo : orderList) if (non.test(orderInfo)) { }
复制代码

Consumer:该接口定义个一个 accept 的抽象方法,没有返回值(void),可以接收任意对象,并对这个对象执行操作


    run(orderInfoList, orderInfo -> { System.out.println("落库"); });
static void run(List<OrderInfo> orderInfoList, Consumer<OrderInfo> consumer) { for (OrderInfo orderInfo : orderInfoList) consumer.accept(orderInfo); }
复制代码

Function:接口定义了 apply 的,接收任意对象,返回任意对象,使用的时候可以将输入对象的信息映射到输出


    List<CouponInfo> build = build(orderInfoList, orderInfo -> new CouponInfo(orderInfo));    System.out.println(build.get(0).toString());
/** * 通过订单信息,构件订单使用的优惠信息 */ public static List<CouponInfo> build(List<OrderInfo> orderInfoList, Function<OrderInfo, CouponInfo> function) { System.out.println("构件CouponInfo"); List<CouponInfo> couponInfos = new ArrayList<>(orderInfoList.size()); for (OrderInfo orderInfo : orderInfoList) { couponInfos.add(function.apply(orderInfo)); } return couponInfos; }
// 输出:构件CouponInfo > CouponInfo{orderId='***', orderAmt=***}
复制代码

小结

本文讲解 lambda 表达式语法、语义,讲解函数式接口是什么,作用是什么,Lambda 表达式的编译原理,以及 Java8 及高版本的函数式接口 Consumer、Function 、Predicate,将会在工作中大量用到

发布于: 2 小时前阅读数: 10
用户头像

物有本末,事有终始。知所先后,则近道矣 2020.03.20 加入

🏆CSDNJava领域优质创作者/阿里云专家博主/华为云享专家 📫就职某大型金融互联网公司后端高级工程师 👍专注于研究计算机底层/Java/架构/设计模式/算法

评论

发布
暂无评论
【函数式编程实战】(三)Lambda表达式原理与函数式接口精讲_Java_小明Java问道之路_InfoQ写作社区