首页 > 编程语言 >25_Java中的Lambda表达式

25_Java中的Lambda表达式

时间:2022-12-16 20:13:22浏览次数:52  
标签:25 Java void System println Lambda public out

Java中的Lambda表达式

()代表此接口中的唯一方法,"->" 指向一个语句块{},{}语句块中表示这个方法的重写

一、函数式编程思想概述

​ 在数学中,函数就是有输入量,输出量的一套计算方案,也就是“拿数据做操作”。

​ 面向对象思想强调的 “必须通过对象的形式来做事情”

​ 函数式思想则尽量忽略面向对象的复杂语法:“强调做什么,而不是以什么形式去做”

​ 而这里说的Lambda表达式就是函数式思想的体现

二、体验Lambda表达式

需求:启动一个线程,在控制台输出一句话:多线程程序启动了

步骤:

1、

​ 定义一个类MyRunnable实现Runnable接口,重写run()方法

​ 创建M有Runnable类对象

​ 创建Thread的类对象,把MyRunnable的对象作为构造方法的参数传递

​ 启动线程

2、

​ 使用匿名内部类

3、

​ 使用Lambda表达式

参考代码:

package com.itheima_01;
//多线程接口实现类
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println("多线程程序启动了");
    }
}
package com.itheima_01;
/*
    需求:启动一个线程,在控制台输出一句话:多线程程序启动了
 */
public class LambdaDemo {
    public static void main(String[] args){
        //一、通过一个实现Runnable接口的实现类,来完成需求
        /*MyRunnable my = new MyRunnable();
        Thread t = new Thread(my);  //通过实现Runnable的自定义类作为构造参数传递
        t.start();  //通过start方法启动多线程*/

        //可以看到,对这样一个简单需求,使用实现类未免有些麻烦(若是多个线程对象都需要这个实现类下的run那这样就可以)
        //使用匿名内存类的方式进行改进
        /*new Thread(new Runnable(){
            @Override
            public void run(){
                System.out.println("多线程程序启动了");
            }
        }).start();*/


        //像这样的一个情况下,接口实现中就只有一个方法需要重写
        //使用Lambda表达式的方式改进 ()->{}
        new Thread(()->{
            System.out.println("多线程程序启动了");
        }).start();
    }
}

三、Lambda表达式的标准格式

1、匿名内部类的写法:

new Thread(new Runnable(){
            @Override
            public void run(){
                System.out.println("多线程程序启动了");
            }
        }).start();

​ 向匿名对象Thread中的有参构造函数传递了一个匿名内部类

​ 方法的参数为空,无返回值,里面的内容表示我们需要完成的事情

2、Lambda表达式写法(对于其而言,重点关注我们需要做什么,而不是创建对象,这也是函数式编程思想):

​ 可见的是对于匿名内部类而言,Lambda表达式省略了创建子类/实现类的过程,只关注完成哪件事。而对于接口而言接口本身的关注点也是在其中的方法,而并非是成员属性即类。

 new Thread(()->{
            System.out.println("多线程程序启动了");
        }).start();

():表示匿名内部类中重写的函数,参数为空

->:用箭头指向函数的具体实现即{}

{}:包含一段代码块,这里是指的函数的实现体

组成Lambda表达式的三要素:形式参数、箭头、代码块

3、Lambda表达式的格式:

(形式参数)->{代码块}

形式参数:与函数(方法)中的差不多,可以使用函数的写法

->:表示一个指向的动作

代码块:是我们具体要做的事情,也就是函数的实现语句

四、Lambda表达式的练习

Lambda表达式的使用前提:

​ 有一个接口

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

练习1:

​ 定义一个接口(Eatable),里面定义一个抽象方法:void eat();

​ 定义一个测试类(EatableDemo),在测试类中提供两个方法

​ 一个方法是:useEatable(Eatable e)

​ 一个方法是主方法,在主方法中调用useEatable方法

参考代码:

package com.itheima_02;
//定义一个接口,其中只有一个抽象方法

public interface Eatable {  //创建一个接口interface
    public abstract void eat(); //在接口中只有一个抽象方法
}
package com.itheima_02;

//定义一个接口的实现类
public class EatableImpl implements Eatable{
    @Override
    public void eat(){
        System.out.println("吃肉");
    }
}
package com.itheima_02;
//主类
public class EatableDemo {
    public static void main(String[] args){
        //调用方法

        //1、传入实现类对象
        EatableDemo.useEatable(new EatableImpl());  //使用了匿名对象

        //2、传入匿名内部类
        EatableDemo.useEatable(new Eatable() {
            @Override
            public void eat() {
                System.out.println("吃水果");
            }
        });

        //3、传入对应的lambda表达式
        EatableDemo.useEatable(()->{
            System.out.println("吃菜");
        });
    }

    //定义一个方法,使用接口作为参数,需要传入一个对应的实现类,进行多态的实现
    public static void useEatable(Eatable eatable){
        eatable.eat();
    }
}

练习2:

​ 定义一个接口(Flyable),里面定义一个抽象方法:void fly(String s);

​ 定义一个测试类(FlyableDemo),在测试类中提供两个方法

​ 一个方法是:useFlyable(Flyable f)

​ 一个方法是主方法,在主方法中调用useFlyable方法

参考代码:

package com.itheima_03;
//接口
public interface Flyable {
    public abstract void fly(String s);
}
package com.itheima_03;
//实现类
public class FlyableImpl implements Flyable{
    @Override
    public void fly(String s){
        System.out.println(s);
    }
}
package com.itheima_03;
//主类
public class FlyableDemo {
    public static void main(String[] args){
        //调用方法
        //使用实现类做参数进行传递
        FlyableDemo.useFlyable(new FlyableImpl());

        //使用匿名内部类作为参数进行传递
        FlyableDemo.useFlyable(new Flyable(){
            @Override
            public void fly(String s){
                System.out.println(s);
            }
        });

        //使用lambda表达式作为参数进行传递
        FlyableDemo.useFlyable((String s)->{    //此处括号中就有参数了
            System.out.println(s);
        });

        FlyableDemo.useFlyable((s)->{   //还可以这样写(省略了数据类型)
            System.out.println(s);
        });

    }

    public static void useFlyable(Flyable flyable){
        flyable.fly("测试输出语句");
    }
}

练习3:

​ 定义一个接口(Addable),里面定义一个抽象方法:int add(int x, int y);

​ 定义一个测试类(AddableDemo),在测试类中提供两个方法

​ 一个方法是:useAddable(Addable a)

​ 一个方法是主方法,在主方法中调用useAddable方法

参考代码:

package com.itheima_04;

public interface Addable {
    public abstract int add(int x, int y);
}
package com.itheima_04;

public class AddableDemo {
    public static void main(String[] args){
        //调用方法
        //使用匿名内部内作为参数传递
        AddableDemo.useAddable(new Addable(){
            @Override
            public int add(int x, int y){
                return x + y;
            }
        });

        //使用lambda表达式进行传递
        AddableDemo.useAddable((int x, int y)->{    //可以看到无需添加一个返回类型在()前,只需要在实现体中return
            return x + y;
        });

        AddableDemo.useAddable((x, y)->{    //可以看到参数类型可以省略
            return x + y;
        });
    }

    public static void useAddable(Addable addable){
        int sum = addable.add(10, 30);
        System.out.println(sum);
    }
}

五、Lambda表达式的省略模式

省略规则:

​ 参数类型可以省略,但是又多个参数的情况下,不能只省略一个

​ 如果参数有且只有一个,那么小括号可以省略

​ 如果代码块语句有且只有一条,可以省略 大阔号 和 分号 ,同时含return时需要省略return

参考代码:

package com.itheima_05;

public interface Addable {
    public abstract int add(int x, int y);
}
package com.itheima_05;

public interface Flyable {
    public abstract void fly(String s);
}
package com.itheima_05;

public class LambdaDemo {
    public static void main(String[] args) {
        //常规写法:
        /*useAddable((int x, int y)->{
            return x + y;
        });*/

        //1、参数类型可以省略
        useAddable((x, y)->{    //且要省略,就所有参数都要省略数据类型
            return x + y;
        });

        //常规写法
        /*useFlyable((String s)->{
            System.out.println(s);
        });*/

        /*useFlyable((s)->{
            System.out.println(s);
        });*/

        //2、如果参数“有且只有一个时”,小括号可以省略
        /*useFlyable(s->{
            System.out.println(s);
        });*/

        //3、如果代码块的语句只有一条,可以省略大括号和分号
        useFlyable(s-> System.out.println(s));

        //只有一条语句 且 这一条语句中含 return 还能吧return省略了
        useAddable((x, y) -> (x + y));
    }

    public static void useFlyable(Flyable flyable){
        flyable.fly("测试输出语句");
    }

    public static void useAddable(Addable addable){
        int sum = addable.add(10, 20);
        System.out.println(sum);
    }
}

六、Lambda表达式的注意事项

注意事项:

​ 使用Lambda必须要有接口,并且要求接口中有且仅有一个抽象方法

​ 必须要有上下文环境,才能推导出Lambda对应的接口

​ 例如:将其传递给一个对应接口对象,或者作为参数向接口形参传递(可以参照一下多态)

参考代码:

package com.itheima_06;

public interface Inter {
    public abstract void show();

    //添加一个抽象方法,发现Lambda表达式便不能使用了
//    public abstract void method();
}
package com.itheima_06;
/*
    lambda表达式的注意事项
 */
public class LambdaDemo {
    public static void main(String[] args){
        //方法定义只有一条语句,进行简写
        //使用Lambda必须要使用接口,而且接口中有且只有一个抽象方法
        useInter(()-> System.out.println("好好学习,天天向上!"));

        //必须有上下文环境,此能够推导出Lambda对应的接口
        /*new Thread(new Runnable(){
            @Override
            public void run(){
                System.out.println("匿名内部类");
            }
        }).start(); //对象调用start方法开始启动多线程*/

        //只有单个Lambda语句时无法推导出其含义(这样的接口很多,天知道你要干嘛)
//        ()-> System.out.println("Lambda表达式");

        //指明赋值给对应接口时(或者作为参数传递等),可以推断出
        //同时可以看出其本质也是一个实现类对象
        Runnable r = ()-> System.out.println("Lambda表达式");
        new Thread(r).start();
    }

    public static void useInter(Inter i){
        i.show();
    }
}

七、Lambda表达式和匿名内部类的区别

所需类型不同:

​ 匿名内部类:可以是接口,也可以是抽象类,还可以是具体类

​ Lambda表达式:只能是接口

使用限制不同:

​ Lambda表达式只能针对只有一个抽象方法的接口

​ 匿名内部类可以针对有多个抽象方法的接口

实现原理不同:

​ 匿名内部类编译后会生成class字节码文件

​ Lambda表达式编译后不会生成一个class字节码文件,对应的字节码文件会在运行的时候动态生成

参考代码:

package com.itheima_07;
/*
    具体类
 */
public class Student {
    public void study(){
        System.out.println("爱生活,爱健康");
    }
}
package com.itheima_07;
/*
    抽象类
 */
public abstract class Animal {
    public abstract void method();
}
package com.itheima_07;
/*
    接口
 */
public interface Inter {
    public abstract void show();

    //运行Lambda时注释
    public abstract void method();

}
package com.itheima_07;
/*
    测试类:
          通过测试类、抽象类、接口来体现
 */
public class LambdaDemo {
    public static void main(String[] args){
        //一、使用匿名内部类
        /*//1、此处匿名内部类,相当于这个具体类的子类,并重写了类中的一个方法
        useStudent(new Student(){
            @Override
            public void study(){
                System.out.println("具体类");
            }
        });

        //2、此处匿名内部类,相当于这个抽象类的子类,并重写了抽象类中的一个方法
        useAnimal(new Animal() {
            @Override
            public void method() {
                System.out.println("抽象类");
            }
        });

        //3、此处匿名内部类,相当于这个接口的实现类,并重写了接口中的一个方法
        useInter(new Inter() {
            @Override
            public void show() {
                System.out.println("接口");
            }
        });*/

        //接口中有两个抽象方法时
        useInter(new Inter() {
            @Override
            public void show() {
                System.out.println("方法一重写");
            }

            @Override
            public void method() {
                System.out.println("方法二重写");
            }
        });

        //二、使用Lambda表达式
        //当接口中在添加一个方法后,无法通过编译
//        useInter(() -> System.out.println("接口"));

//        useAnimal(() -> System.out.println("抽象类"));   //无法通过编译

//        useStudent(() -> System.out.println("具体类"));  //无法通过编译


        //三、匿名内部类编译后会生成一个字节码文件,而Lambda表达式不会
        //LambdaDemo$1.class    (通过模块目录下的out文件运行后比对查看)

    }

    private static void useStudent(Student s){
        s.study();
    }

    private static void useAnimal(Animal a){
        a.method();
    }

    private static void useInter(Inter i){
        //此处值调用了show()方法
        i.show();
    }
}

标签:25,Java,void,System,println,Lambda,public,out
From: https://www.cnblogs.com/fragmentary/p/16988210.html

相关文章

  • oracle数据库startup启动报错ORA-27125 unable to create shared memory segment
    问题描述:oracle数据库startup启动报错ORA-27125unabletocreatesharedmemorysegment,如下所示:系统:suse11.2环境:rac双节点+oracle11.2.0.4说明:节点1数据库正常,节点2......
  • k倍区间【第八届蓝桥杯省赛C++B组,第八届蓝桥杯省赛JAVAB组】
    k倍区间给定一个长度为\(N\)的数列,\(A1,A2,…AN\),如果其中一段连续的子序列\(Ai,Ai+1,…Aj\)之和是\(K\)的倍数,我们就称这个区间\([i,j]\)是\(K\)倍区间。你能......
  • Centos 7.9 基于二进制文件部署kubernetes v1.25.5集群
    简述Kubernetes(简称为:k8s)是Google在2014年6月开源的一个容器集群管理系统,使用Go语言开发,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用......
  • java常用类库(API)
    该章节学习方法:不要背,只需要将具体方法的作用记下来,需要用的时候直接查文档API的使用和常用包的概述java.lang包,是java语言的核心包,包中的所有内容由java虚拟机自动导......
  • Java同步器简述
    一、概述在并发编程领域,有两大核心问题:一个是互斥,即同一时刻只允许一个线程访问共享资源;另一个是同步,即线程之间如何通信、协作。主要原因是,对于多线程实现实现并发,一直以......
  • JAVA结业测试题及答案
    JAVA结业试题二1下列哪些方法互为重载方法,哪些方法是覆盖方法。答案用号码标识:4分publicclassA{  ①publicstaticvoidmethod(Stringstr){};  ②protected int......
  • JAVA面试题-CORE JAVA部分
    JAVA面试题-COREJAVA部分                   --感谢SD0501班毕业学员李晓宾的提供,希望对面试学员和在校学员有所帮助。1. 在main(String[]args)方法内......
  • JavaScript中this关键字使用方法详解
       在面向对象编程语言中,对于this关键字我们是非常熟悉的。比如C++、C#和Java等都提供了这个关键字,虽然在开始学习的时候觉得比较难,但只要理解了,用起来是非常方便和意义......
  • java编码工具
    3.编码工具​工欲善其事,必先利其器。目前编码工具琳琅满目,大家可根据自己需求自己选择工具。3.1文本编辑器收费UltraEditEditPlus免费​subli......
  • Android Studio工程目录介绍,Ubuntu/Debian 系统切换Java(JVM),修改Java版本,JAVA_HOME
    AndroidStudio工程目录介绍 du1@dePc:~/asProjs/sms$./gradlewcleanERROR:JAVA_HOMEissettoaninvaliddirectory:/home/du1/aset/as/sdkPleasesettheJAVA......