Java_Lambda表达式JDK8新特性(方法引用)

news2024/11/26 14:24:36

一、Lambda表达式

接下来,我们学习一个JDK8新增的一种语法形式,叫做Lambda表达式。作用:用于简化匿名内部类代码的书写。

1.1 Lambda表达式基本使用

怎么去简化呢?Lamdba是有特有的格式的,按照下面的格式来编写Lamdba。

(被重写方法的形参列表) -> {
    被重写方法的方法体代码;
}

在这里插入图片描述

需要给说明一下的是,在使用Lambda表达式之前,必须先有一个接口,而且接口中只能有一个抽象方法。(注意:不能是抽象类,只能是接口)

像这样的接口,我们称之为函数式接口,只有基于函数式接口的匿名内部类才能被Lambda表达式简化。

函数式接口:首先是一个接口,并且该接口里面有且仅有一个抽样方法。以上代码中Animal压根不是一个接口,而是一个类,是不可以被lambda表达式简化的

public interface Swimming{//接口
    void swim();//有且仅有一个抽样方法
}

有了以上的Swimming接口之后,接下来才能再演示,使用Lambda表达式,简化匿名内部类书写。

public class LambdaTest1 {
    public static void main(String[] args) {
        // 目标:认识Lambda表达式.
        //1.创建一个Swimming接口的匿名内部类对象
        Swimming s = new Swimming(){
             @Override
             public void swim() {
                 System.out.println("学生快乐的游泳~~~~");
             }
         };
         s.swim();
         
        //2.使用Lambda表达式对Swimming接口的匿名内部类进行简化
        Swimming s1 = () -> {
              System.out.println("学生快乐的游泳~~~~");
        };
        s1.swim();
    }
}

在这里插入图片描述

好的,我们现在已经知道Lamdba表达式可以简化基于函数式接口的匿名内部类的书写。接下来,我们可以把刚才使用Arrays方法时的代码,使用Lambda表达式简化一下了。

public class LambdaTest2 {
    public static void main(String[] args) {
        // 目标:使用Lambda简化函数式接口。
        double[] prices = {99.8, 128, 100};
        //1.把所有元素*0.8: 先用匿名内部类写法
        Arrays.setAll(prices, new IntToDoubleFunction() {
            @Override
            public double applyAsDouble(int value) {
                // value = 0  1  2
                return prices[value] * 0.8;
            }
        });
        //2.把所有元素*0.8: 改用Lamdba表达式写法
        Arrays.setAll(prices, (int value) -> {
                return prices[value] * 0.8;
        });
 
        System.out.println(Arrays.toString(prices));
        System.out.println("-----------------------------------------------");
         
        Student[] students = new Student[4];
        students[0] = new Student("蜘蛛精", 169.5, 23);
        students[1] = new Student("紫霞", 163.8, 26);
        students[2] = new Student("紫霞", 163.8, 26);
        students[3] = new Student("至尊宝", 167.5, 24);
        //3.对数组中的元素按照年龄升序排列: 先用匿名内部类写法
        Arrays.sort(students, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return Double.compare(o1.getHeight(), o2.getHeight()); // 升序
            }
        });
        //4.对数组中的元素按照年龄升序排列: 改用Lambda写法
        Arrays.sort(students, (Student o1, Student o2) -> {
                return Double.compare(o1.getHeight(), o2.getHeight()); // 升序
        });
        System.out.println(Arrays.toString(students));
    }
}

1.2 Lambda表达式省略规则

在这里插入图片描述

刚才我们学习了Lambda表达式的基本使用。Java觉得代码还不够简单,于是还提供了Lamdba表达式的几种简化写法。具体的简化规则如下

1.Lambda的标准格式
    (参数类型1 参数名1, 参数类型2 参数名2)->{
        ...方法体的代码...
        return 返回值;
    }
 
2.在标准格式的基础上()中的参数类型可以直接省略
    (参数名1, 参数名2)->{
        ...方法体的代码...
        return 返回值;
    }
     
3.如果{}总的语句只有一条语句,则{}可以省略、return关键字、以及最后的“;”都可以省略
    (参数名1, 参数名2)-> 结果
     
4.如果()里面只有一个参数,则()可以省略
    (参数名)->结果

接下来从匿名内部类开始、到Lambda标准格式、再到Lambda简化格式,一步一步来简化一下。同学们体会一下简化的过程。

public class LambdaTest2 {
    public static void main(String[] args) {
        // 目标:使用Lambda简化函数式接口。
        double[] prices = {99.8, 128, 100};
        //1.对数组中的每一个元素*0.8: 匿名内部类写法
        Arrays.setAll(prices, new IntToDoubleFunction() {
            @Override
            public double applyAsDouble(int value) {
                // value = 0  1  2
                return prices[value] * 0.8;
            }
        });
        //2.需求:对数组中的每一个元素*0.8,使用Lambda表达式标准写法
        Arrays.setAll(prices, (int value) -> {
                return prices[value] * 0.8;
        });
        //3.使用Lambda表达式简化格式1——省略参数类型
        Arrays.setAll(prices, (value) -> {
            return prices[value] * 0.8;
        });
        //4.使用Lambda表达式简化格式2——省略()
        Arrays.setAll(prices, value -> {
            return prices[value] * 0.8;
        });
        //5.使用Lambda表达式简化格式3——省略{}
        Arrays.setAll(prices, value -> prices[value] * 0.8 );
 
        System.out.println(Arrays.toString(prices));
         
        System.out.println("------------------------------------
 
        Student[] students = new Student[4];
        students[0] = new Student("蜘蛛精", 169.5, 23);
        students[1] = new Student("紫霞", 163.8, 26);
        students[2] = new Student("紫霞", 163.8, 26);
        students[3] = new Student("至尊宝", 167.5, 24);
         
        //1.使用匿名内部类
        Arrays.sort(students, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return Double.compare(o1.getHeight(), o2.getHeight()); // 升序
            }
        });
        //2.使用Lambda表达式表达式——标准格式
        Arrays.sort(students, (Student o1, Student o2) -> {
                return Double.compare(o1.getHeight(), o2.getHeight()); // 升序
        });
        //3.使用Lambda表达式表达式——省略参数类型
        Arrays.sort(students, ( o1,  o2) -> {
            return Double.compare(o1.getHeight(), o2.getHeight()); // 升序
        });
        //4.使用Lambda表达式表达式——省略{}
        Arrays.sort(students, ( o1,  o2) -> Double.compare(o1.getHeight(), o2.getHeight()));
 
 
        System.out.println(Arrays.toString(students));
    }
}

二、JDK8新特性(方法引用)

我们知道Lambda是用来简化匿名代码的书写格式的,而方法引用是用来进一步简化Lambda表达式的,它简化的更加过分。

到这里有小伙伴可能就想慰问Java爸爸了:“之前的代码挺好的呀!好不容易学会,你又来搞这些,把我都搞晕了。“ 说句大实话,确实有这样的问题,学习新的东西肯定会增加我们的学习成本,从心理上来说多少是有写抗拒的。但是从另一个角度想,一旦我们学会了,会大大简化我们的代码书写,提高我们编写代码的效率,而且这些新的语法都是有前提条件的,遇到的时候就简化得了。再退一步想,就算你没有学会,还是用以前的办法一点问题也没有。

给大家交代清楚了,学习方法引用可能存在的一些心理特点之后,接下来我们再正式学习方法引用的代码怎么编写。

2.1 静态方法引用

我们先学习静态方法的引用,还是用之前Arrays代码来做演示。现在准备好下面的代码

public class Test1 {
    public static void main(String[] args) {
        Student[] students = new Student[4];
        students[0] = new Student("蜘蛛精", 169.5, 23);
        students[1] = new Student("紫霞", 163.8, 26);
        students[2] = new Student("紫霞", 163.8, 26);
        students[3] = new Student("至尊宝", 167.5, 24);
 
        // 原始写法:对数组中的学生对象,按照年龄升序排序
        Arrays.sort(students, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.getAge() - o2.getAge(); // 按照年龄升序排序
            }
        });
 
        // 使用Lambda简化后的形式
        Arrays.sort(students, (o1, o2) -> o1.getAge() - o2.getAge());
    }
}

准备另外一个类CompareByData类,用于封装Lambda表达式的方法体代码;

public class CompareByData {
    public static int compareByAge(Student o1, Student o2){
        return o1.getAge() - o2.getAge(); // 升序排序的规则
    }
}

现在我们就可以把Lambda表达式的方法体代码,改为下面的样子

Arrays.sort(students, (o1, o2) -> CompareByData.compareByAge(o1, o2));

Java为了简化上面Lambda表达式的写法,利用方法引用可以改进为下面的样子。实际上就是用类名调用方法,但是把参数给省略了。 这就是静态方法引用

//静态方法引用:类名::方法名
Arrays.sort(students, CompareByData::compareByAge);

2.2 实例方法引用

还是基于上面的案例,我们现在来学习一下实例方法的引用。

在CompareByData类中,再添加一个实例方法,用于封装Lambda表达式的方法体
在这里插入图片描述

接下来,我们把Lambda表达式的方法体,改用对象调用方法

CompareByData compare = new CompareByData();
Arrays.sort(students, (o1, o2) -> compare.compareByAgeDesc(o1, o2)); // 降序

最后,再将Lambda表达式的方法体,直接改成方法引用写法。实际上就是用类名调用方法,但是省略的参数。这就是实例方法引用

CompareByData compare = new CompareByData();
Arrays.sort(students, compare::compareByAgeDesc); // 降序

2.3 特定类型的方法引用

在学习之前还是需要给大家说明一下,这种特定类型的方法引用是没有什么道理的,只是语法的一种约定,遇到这种场景,就可以这样用。

Java约定:
    如果某个Lambda表达式里只是调用一个实例方法,并且前面参数列表中的第一个参数作为方法的主调,    后面的所有参数都是作为该实例方法的入参时,则就可以使用特定类型的方法引用。
格式:
    类型::方法名
public class Test2 {
    public static void main(String[] args) {
        String[] names = {"boby", "angela", "Andy" ,"dlei", "caocao", "Babo", "jack", "Cici"};
         
        // 要求忽略首字符大小写进行排序。
        Arrays.sort(names, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                // 制定比较规则。o1 = "Andy"  o2 = "angela"
                return o1.compareToIgnoreCase(o2);
            }
        });
         
        //lambda表达式写法
        Arrays.sort(names, ( o1,  o2) -> o1.compareToIgnoreCase(o2) );
        //特定类型的方法引用!
        Arrays.sort(names, String::compareToIgnoreCase);
 
        System.out.println(Arrays.toString(names));
    }
}

2.4 构造器引用

各位小伙伴,我们学习最后一种方法引用的形式,叫做构造器引用。还是先说明一下,构造器引用在实际开发中应用的并不多,目前还没有找到构造器的应用场景。所以大家在学习的时候,也只是关注语法就可以了。

现在,我们准备一个JavaBean类,Car类

public class Car {
    private String name;
    private double price;
 
    public Car() {
 
    }
 
    public Car(String name, double price) {
        this.name = name;
        this.price = price;
    }
 
    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 "Car{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

因为方法引用是基于Lamdba表达式简化的,所以也要按照Lamdba表达式的使用前提来用,需要一个函数式接口,接口中代码的返回值类型是Car类型

interface CreateCar{
    Car create(String name, double price);
}

最后,再准备一个测试类,在测试类中创建CreateCar接口的实现类对象,先用匿名内部类创建、再用Lambda表达式创建,最后改用方法引用创建。同学们只关注格式就可以,不要去想为什么(语法就是这么设计的)。

public class Test3 {
    public static void main(String[] args) {
        // 1、创建这个接口的匿名内部类对象。
        CreateCar cc1 = new CreateCar(){
            @Override
            public Car create(String name, double price) {
                return new Car(name, price);
            }
        };
        //2、使用匿名内部类改进
        CreateCar cc2 = (name,  price) -> new Car(name, price);
 
        //3、使用方法引用改进:构造器引用
        CreateCar cc3 = Car::new;
         
        //注意:以上是创建CreateCar接口实现类对象的几种形式而已,语法一步一步简化。
         
        //4、对象调用方法
        Car car = cc3.create("奔驰", 49.9);
        System.out.println(car);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1319281.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何用Python向图像中加入噪声

我们在做机器视觉项目的过程中&#xff0c;有的时候需要向图像中加入噪声。Pytorch本身不支持类似的功能&#xff0c;如果自己写的话&#xff0c;不但麻烦&#xff0c;而且容易出错。好在skimage支持这个功能。代码如下&#xff1a; import skimage import matplotlib.pyplot …

Web安全漏洞分析—文件包含

在当今数字化时代&#xff0c;随着Web应用程序的广泛应用&#xff0c;网络安全问题愈加凸显。其中&#xff0c;文件包含漏洞作为一种常见但危险的安全隐患&#xff0c;为恶意攻击者提供了可乘之机。在这篇博客中&#xff0c;我们将深入探讨文件包含漏洞的本质、攻击手法以及应对…

信息收集 - 域名

1、Whois查询: Whois 是一个用来查询域名是否已经被注册以及相关详细信息的数据库(如:域名所有人、域名注册商、域名注册日期和过期日期等)。通过访问 Whois 服务器,你可以查询域名的归属者联系方式和注册时间。 你可以在 域名Whois查询 - 站长之家 上进行在线查询。 2、…

python提取图片型pdf中的文字(提取pdf扫描件文字)

前言 文字型pdf提取&#xff0c;python的库一大堆&#xff0c;但是图片型pdf和pdf扫描件提取&#xff0c;还是有些难度的&#xff0c;我们需要用到OCR&#xff08;光学字符识别&#xff09;功能。 一、准备 1、安装OCR&#xff08;光学字符识别&#xff09;支持库 首先要安…

详解git pull和git fetch的区别

git pull和git fetch的区别, 网上人云亦云胡说八道的实在是太多了&#xff0c;误导我很久。 今天看到一个说得好的&#xff0c;记录一下。 前言 在我们使用git的时候用的更新代码是git fetch&#xff0c;git pull这两条指令。但是有没有小伙伴去思考过这两者的区别呢&#xff…

vue3引入Echarts图表

说明&#xff1a;echarts是父组件&#xff0c;stack是子组件&#xff0c;将stack引入到echarts文件中 查看echarts.vue时可看到stack.vue中的图表 # # # 引入方式 第一步 Echarts官网&#xff1a;快速上手 - 使用手册 - Apache ECharts 第二步 在控制台安装Echarts模块…

8.完成任务实现的SDK封装及插件式加载

1.设计 任务的实现目前完成了Modbus RTU、Modbus TCP、Virtule。任务实现应该是任意的&#xff0c;比如打印一段话&#xff0c;执行一句SQL等&#xff0c;所以系统内部的必然要做到可扩展。 要做到可扩展&#xff0c;首先第一步就是定义标准&#xff0c;所以我们首先需要封装…

nodejs+vue+微信小程序+python+PHP基于大数据的银行信用卡用户的数仓系统的设计与实现-计算机毕业设计推荐

银行信用卡用户的数仓系统综合网络空间开发设计要求。目的是将银行信用卡用户的数仓系统从传统管理方式转换为在网上管理&#xff0c;完成银行信用卡用户的数仓管理的方便快捷、安全性高、交易规范做了保障&#xff0c;目标明确。银行信用卡用户的数仓系统可以将功能划分为管理…

从文字下乡到人人学英语

从建国到改革开放&#xff0c;从恢复高考到新式教育改革&#xff0c;中国飞速发展&#xff0c;文字需求也在不断增大&#xff0c;在“地球村”的时代下&#xff0c;我们要“习文字之变&#xff0c;顺时代发展。” 古言道&#xff1a;“仓颉作书&#xff0c;后稷作稼”&#xff…

【Spark面试】Spark面试题答案

目录 1、spark的有几种部署模式&#xff0c;每种模式特点&#xff1f;&#xff08;☆☆☆☆☆&#xff09; 2、Spark为什么比MapReduce块&#xff1f;&#xff08;☆☆☆☆☆&#xff09; 3、简单说一下hadoop和spark的shuffle相同和差异&#xff1f;&#xff08;☆☆☆☆☆…

Linux学习教程(第十三章 Linux数据备份与恢复)

第十三章 Linux数据备份与恢复 不知道大家有没有丢失过重要的数据呢&#xff1f; 丢失数据的理由是多种多样的&#xff0c;有人是因为重装系统时&#xff0c;没有把加密文件的密钥导出&#xff0c;重装系统后密钥丢失&#xff0c;导致所有的加密数据不能解密&#xff1b;也有人…

实验记录:深度学习模型收敛速度慢有哪些原因

深度学习模型收敛速度慢有哪些原因&#xff1f; 学习率设置不当&#xff1a; 学习率是算法中一个重要的超参数&#xff0c;它控制模型参数在每次迭代中的更新幅度。如果学习率过大&#xff0c;可能会导致模型在训练过程中的振荡&#xff0c;进而影响到收敛速度&#xff1b;如果…

字符设备驱动框架的编写

一. 简介 我们在学习裸机或者 STM32 的时候关于驱动的开发就是初始化相应的外设寄存器&#xff0c;在 Linux 驱动开发中&#xff0c;肯定也是要初始化相应的外设寄存器。 只是在 Linux 驱动开发中&#xff0c; 我们需要按照其规定的框架来编写驱动&#xff0c;所以说学 …

【网络安全】网络防护之旅 - Java安全机制探秘与数字证书引爆网络防线

&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《网络安全之道 | 数字征程》⏰墨香寄清辞&#xff1a;千里传信如电光&#xff0c;密码奥妙似仙方。 挑战黑暗剑拔弩张&#xff0c;网络战场誓守长。 目录 &#x1f608;1. 初识网络安…

机场信息集成系统系列介绍(3):机场运行核心数据库(AODB)

目录 1、背景&#xff1a;什么是AODB 2、AODB包括哪些内容 3、AODB还应该适配哪些场景 4、一点点拓展 机场运行核心数据库&#xff08;AODB&#xff09;Airport Operation DataBase 1、背景&#xff1a;什么是AODB 在机场繁重的航班保障和旅客服务背后&#xff0c;庞大的…

centos安装了curl却报 -bash: curl: command not found

前因 我服务器上想用curl下载docker-compress&#xff0c;发现没有curl命令&#xff0c;就去下载安装&#xff0c;安装完成之后&#xff0c;报-bash: curl: command not found 解决方法 [rootcentos ~]# rpm -e --nodeps curl warning: file /usr/bin/curl: remove failed: …

非常好用的C++跨平台网络通信Mongoose,随笔记录

简介 Mongoose 是一个 C/C 网络库。它实现了事件驱动&#xff0c; TCP、UDP、HTTP、WebSocket、MQTT 的非阻塞 API。它连接设备 并将它们带到网上。自 2004 年以来&#xff0c;一些开源和商业 产品已经利用了它。它甚至运行在 国际空间站&#xff01; Mongoose 使嵌入式网络编…

【数据结构】(堆)Top-k|堆排序

目录 概念&#xff1a; 堆的实现 构建 初始化 销毁 插入元素 往上调整 删除堆顶元素 往下调整 返回堆顶元素 返回有效个数 是否为空 堆排序 Top-k问题 ​编辑 创建数据 堆top-k 概念&#xff1a; 堆是将数据按照完全二叉树存储方式存储到一维数组中&#xff…

Python实验项目9 :网络爬虫与自动化

实验 1&#xff1a;爬取网页中的数据。 要求&#xff1a;使用 urllib 库和 requests 库分别爬取 http://www.sohu.com 首页的前 360 个字节的数据。 # 要求&#xff1a;使用 urllib 库和 requests 库分别爬取 http://www.sohu.com 首页的前 360 个字节的数据。 import urllib.r…

网络 / day02 作业

1. TCP和UDP通信模型 1.1 TCP server #include <myhead.h>#define PORT 9999 #define IP "192.168.250.100"int main(int argc, const char *argv[]) {//1. create socketint sfd -1;if( (sfd socket(AF_INET, SOCK_STREAM, 0 ))-1 ){perror("socke…