• JDK1.8新特性---Lambda表达式


    参考链接:

           Lambda表达式本质上是一段匿名内部类,也可称为闭包,我们可以将Lambda表达式理解为一段可以传递的代码(将代码像数据一样传递),使用它可以写出简洁、灵活的代码,作为一种更紧凑的代码风格,使java语言表达能力得到提升。

           Lambda表达式在java语言中引入了一种新的语法元素和操作,允许把函数作为一个方法的参数(函数作为参数传递进方法中),Lambda表达式操作符为“->”(也称箭头操作符)。它将Lambda表达式分割为两部分, 左边:指Lambda表达式的所有参数,右边:指Lambda体,即表示Lambda表达式需要执行的功能。即:传入参数->利用参数执行功能

    lambda表达式的重要特征如下:

    • 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。

    • 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。

    • 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。

    • 可选的返回关键字:如果主体只有一个表达式返回值,则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。

    0. Lambda标准格式

    Lambda省去了面向对象的条条框框,Lambda的标准格式格式由3个部分组成:

    (参数类型 参数名称) -> {

    代码体;

    }

    格式说明:

    • (参数类型 参数名称):参数列表

    • {代码体;}:方法体

    • -> :箭头:分隔参数列表和方法体

    0.1 使用前提条件

    Lambda的语法非常简洁,但是Lambda表达式不是随便使用的,使用时有几个条件要特别注意:

    • 方法的参数或局部变量类型必须为接口才能使用Lambda

    • 接口中有且仅有一个抽象方法

    举例:

    • 设计一个接口,接口中定义一个抽象方法

     public interface Flyable { 
         public abstract void flying(); 
     } 
    • 测试类

     public class TestFlyable {
         public static void main(String[] args) {
             test01(() -> {
             });
     ​
             Flyable s = new Flyable() {
                 @Override
                 public void flying() {
                 }
             };
     ​
             Flyable s2 = () -> {
             };
         }
     ​
         public static void test01(Flyable fly) {
             fly.flying();
         }
     }

    0.2 省略形式

    在Lambda标准格式的基础上,使用省略写法的规则为:

    • 小括号内参数的类型可以省略

    • 如果小括号内有且仅有一个参数,则小括号可以省略

    • 如果大括号内有且仅有一个语句,可以同时省略大括号、return关键字及语句分号

    举例:

     (int a) -> { 
         return new Student(); 
     } 

    省略后

     a -> new Student()

    0.3 其它

    • lambda表达式访问局部变量 ,变量的引用可以不用final来修饰 ,但作用与final一样,不能被改变。

    • lambda表达式中不允许内参数与外参数命名相同

    0.4 Lambda和匿名内部类对比

    • 所需的类型不一样

      • 匿名内部类需要的类型可以是类、抽象类、接口

      • Lambda表达式需要的类型必须是接口

    • 抽象方法的数量不一样

      • 匿名内部类所需的接口中抽象方法的数量随意

      • Lambda表达式所需的接口只能有一个抽象方法

    • 实现原理不同

      • 匿名内部类是在编译后会形成class

      • Lambda表达式是在程序运行的时候动态生成class

    具体使用如下:

    1. 无输入参数,无返回值

    格式:()->

    举例说明:

     package lambda;
     ​
     import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
     ​
     /**
      * @ClassName Test01
      * @Description TODO
      * @Author Jiangnan Cui
      * @Date 2022/9/18 9:43
      * @Version 1.0
      */
     public class Test01 {
         // 使用log4j需要导入slf4j-log4j12、log4j的jar包,同时编写log4j的配置文件log4j.properties
         private static Logger log = LoggerFactory.getLogger(Test01.class);
         public static void main(String[] args) {
             /**
              * Runnable接口是线程辅助类,仅定义了一个方法run()方法
              * 并且不接受任何参数,不返回任何值。
              */
             // 使用匿名内部类形式创建Runnable实现类
             Runnable t1 =new Runnable(){
                 @Override
                 public void run(){
                     log.info("我是没有使用Lambda表达式:不简洁");
                 }
             };
     ​
             // 使用lambda表达式简化匿名内部类形式创建Runnable实现类
             Runnable t2 = () -> log.info("我是使用Lambda表达式:简洁、灵活");
     ​
             t1.run();
             t2.run();
         }
     }
     ​

    输出结果:

     [main] INFO lambda.Test01 - 我是没有使用Lambda表达式:不简洁
     [main] INFO lambda.Test01 - 我是使用Lambda表达式:简洁、灵活

    附:

    • log4j依赖

     
         org.slf4j
         slf4j-log4j12
         1.7.25
     
     
         log4j
         log4j
         1.2.17
     
    • log4j.properties

     # Configure logging for testing: optionally with log file
     ​
     #log4j.rootLogger=debug,appender
     log4j.rootLogger=info,appender  
     #log4j.rootLogger=error,appender
     ​
     #\u8F93\u51FA\u5230\u63A7\u5236\u53F0
     log4j.appender.appender=org.apache.log4j.ConsoleAppender  
     #\u6837\u5F0F\u4E3ATTCCLayout
     log4j.appender.appender.layout=org.apache.log4j.TTCCLayout

    2. 一个输入参数,无返回值

    格式:(a)->

    举例说明:

     package lambda;
     ​
     import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
     import java.util.function.Consumer;
     /**
      * @ClassName Demo03
      * @Description TODO
      * @Author Jiangnan Cui
      * @Date 2022/9/18 10:12
      * @Version 1.0
      */
     public class Demo03 {
         private static Logger log = LoggerFactory.getLogger(Demo03.class);
     ​
         public static void main(String[] args) {
             // 使用匿名内部类形式创建Consumer实例
             Consumer consumer = new Consumer() {
                 @Override
                 public void accept(String s) {
                     log.info(s);
                 }
             };
             consumer.accept("爱与被爱的区别");
     ​
             // 使用lambda表达式简化匿名内部类形式创建Consumer实例
             Consumer consumer1 = (s)->log.info(s);
             consumer1.accept("接受爱不一定爱对方,爱一定付出真心爱");
         }
     }

    输出结果:

     [main] INFO lambda.Demo03 - 爱与被爱的区别
     [main] INFO lambda.Demo03 - 接受爱不一定爱对方,爱一定付出真心爱

    3. 一个输入参数时,输入参数外面()可以省略

    格式:a->

     // 使用lambda表达式简化匿名内部类形式创建Consumer实例
     Consumer consumer2 = s->log.info(s);
     consumer2.accept("无论结果怎样,请相信爱,放手去爱");

    输出结果:

     [main] INFO lambda.Demo03 - 无论结果怎样,请相信爱,放手去爱

    4. 两个输入参数,无返回值

    格式:(a,b)->

    举例说明:

     package lambda;
     ​
     import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
     ​
     import java.util.Comparator;
     ​
     public class Demo05 {
         private static Logger log = LoggerFactory.getLogger(Demo05.class);
     ​
         public static void main(String[] args) {
             CompareOldMethod(12,10);
             findMaxValue(12,10);
             findMinValue(12,10);
         }
         
         // 使用匿名内部类形式创建Comparator实例比较大小
         public static void CompareOldMethod(int num1,int num2){
             Comparator comparator = new Comparator() {
                 @Override
                 public int compare(Integer o1, Integer o2) {
                     log.info("o1:{}",o1);
                     log.info("o2:{}",o2);
                     return o1 < o2 ? o2 : o1;
                 }
             };
             log.info("OldFindMaxValue:{}",comparator.compare(num1,num2));
         }
     ​
         // 使用lambda表达式简化匿名内部类形式创建Comparator实例比较大小
         public static void findMaxValue(int num1,int num2){
             Comparator comparatorMax = (o1, o2) ->{
                 log.info("o1:{}",o1);
                 log.info("o2:{}",o2);
                 return o1 < o2 ? o2 : o1;
             };
             log.info("findMaxValue:{}",comparatorMax.compare(num1,num2));
         }
         
         public static void findMinValue(int num1,int num2){
             Comparator comparatorMin = (o1,o2)->{
                 log.info("o1:{}",o1);
                 log.info("o2:{}",o2);
                 return o1 < o2 ? o1 : o2;
             };
             log.info("findMinValue:{}",comparatorMin.compare(num1,num2));
         }
     }

    输出结果:

     [main] INFO lambda.Demo05 - o1:12
     [main] INFO lambda.Demo05 - o2:10
     [main] INFO lambda.Demo05 - OldFindMaxValue:12
     [main] INFO lambda.Demo05 - o1:12
     [main] INFO lambda.Demo05 - o2:10
     [main] INFO lambda.Demo05 - findMaxValue:12
     [main] INFO lambda.Demo05 - o1:12
     [main] INFO lambda.Demo05 - o2:10
     [main] INFO lambda.Demo05 - findMinValue:10

    5. lambda体只有一条语句时,return和{}均可省略

    举例说明:输出结果同上

     package lambda;
     ​
     import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
     ​
     import java.util.Comparator;
     ​
     public class Demo05 {
         private static Logger log = LoggerFactory.getLogger(Demo05.class);
     ​
         public static void main(String[] args) {
             CompareOldMethod(12,10);
             findMaxValue(12,10);
             findMinValue(12,10);
         }
     ​
         // 使用匿名内部类形式创建Comparator实例比较大小
         public static void CompareOldMethod(int num1,int num2){
             Comparator comparator = new Comparator() {
                 @Override
                 public int compare(Integer o1, Integer o2) {
                     log.info("o1:{}",o1);
                     log.info("o2:{}",o2);
                     return o1 < o2 ? o2 : o1;
                 }
             };
             log.info("OldFindMaxValue:{}",comparator.compare(num1,num2));
         }
     ​
         // 使用lambda表达式简化匿名内部类形式创建Comparator实例比较大小
         public static void findMaxValue(int num1,int num2){
             Comparator comparatorMax = (o1, o2) -> o1 < o2 ? o2 : o1;
             log.info("findMaxValue:{}",comparatorMax.compare(num1,num2));
         }
     ​
         public static void findMinValue(int num1,int num2){
             Comparator comparatorMin = (o1,o2)->o1 < o2 ? o1 : o2;
             log.info("findMinValue:{}",comparatorMin.compare(num1,num2));
         }
     }

    6. 类型判断

    举例说明:

     package lambda;
     ​
     import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
     import java.util.function.Consumer;
     ​
     public class Demo07 {
         private static Logger log = LoggerFactory.getLogger(Demo07.class);
     ​
         public static void main(String[] args) {
             dateType();
         }
     ​
         public static void dateType(){
             // 指明输入参数为String类型
             Consumer consumer = (String s) -> log.info(s);
             consumer.accept("我是指定了输入类型的");
     ​
             // 不指明输入参数类型
             Consumer consumer1 = (s) -> log.info(s);
             consumer1.accept("我没有指定输入类型哦");
         }
     }

    输出结果:

     [main] INFO lambda.Demo07 - 我是指定了输入类型的
     [main] INFO lambda.Demo07 - 我没有指定输入类型哦

    结论:数据类型可以省略,因为编译器可以推断得出,成为“类型推断”。

    7. 举例

    7.1 创建线程

           当需要启动一个线程去完成任务时,通常会通过 Runnable 接口来定义任务内容,并使用 Thread 类来启动该线程。

    传统写法:

     package com.zhq.test;
      
     public class Lambda01 {
         public static void main(String[] args) {
              /*
              一、使用匿名内部类存在的问题
                 public Thread(Runnable target)
              二、匿名内部类做了哪些事情
                  1.定义了一个没有名字的类
                  2.这个类实现了Runnable接口
                  3.创建了这个类的对象
              以上可以看出:
                  1.使用匿名内部类语法是很冗余的
                  2.其实我们最关注的是run方法和里面要执行的代码.
              */
             new Thread(new Runnable() {
                 @Override
                 public void run() {
                     System.out.println("匿名内部类方式");
                 }
             }).start();
         }
     }

            由于面向对象的语法要求,首先创建一个 Runnable 接口的匿名内部类对象来指定线程要执行的任务内容,再将其 给一个线程来启动。

    代码分析:

    对于Runnable的匿名内部类用法,可以分析出几点内容:

    1. Thead 类需要 Runnable 接口作为参数,其中的抽象 run 方法是用来指定线程任务内容的核心。

    2. 为了指定 run 的方法体,不得不需要 Runnable 接口的实现类

    3. 为了省去定义一个 Runnable 实现类的麻烦,不得不使用匿名内部类

    4. 必须覆盖重写抽象 run 方法,所以方法名称、方法参数、方法返回值不得不再写一遍,且不能写错,而实际上,似乎只有方法体才是关键所在。

    优化后:

     public class Lambda01 {
         public static void main(String[] args) {
             // Lambda表达式体现的是函数式编程思想,只需要将要执行的代码放到函数中(函数就是类中
             new Thread(() -> {
                 System.out.println("Lambda表达式");
             }).start();
         }
     }

           通过了解匿名内部类语法冗余,体验了Lambda表达式的使用,发现Lambda是对匿名内部类的简写。

  • 相关阅读:
    Minecraft 我的世界 .minecraft下的各个文件夹的用处
    云原生|kubernetes|kubeadm部署高可用集群(二)---kube-apiserver高可用+etcd外部集群
    APS计划排程在半导体行业的应用
    对 Git 分支 master 和 origin/master 的一些认识
    已解决:Python Error: IndentationError: expected an indented block 问题
    安防监控用品经营商城小程序搭建
    Hadoop运行环境搭建(开发重点)、VMware 安装
    tinyxml2使用
    maven
    pyserial,win11,串口总是被占用
  • 原文地址:https://blog.csdn.net/xiaocui1995/article/details/126916061