【javaSE-语法】lambda表达式

news2024/9/29 21:28:17

【javaSE-语法】lambda表达式

  • 1. 先回忆一下:
    • 1.1 接口不能直接通过关键字new进行实例化
    • 1.2 函数式接口
    • 1.3 匿名内部类
      • 1.31 匿名内部类在代码中长啥样?
      • 1.32 构造一个新的对象与构造一个扩展了某类的匿名内部类的对象,两者有什么区别?
      • 1.33 如何调用匿名内部类对象中的成员
      • 1.34 匿名内部类的变量捕获
  • 2. lambda表达式
    • 2.1 语法
    • 2.2 基本使用
    • 2.3 lambda的变量捕获
    • 2.4 lambda在集合中的使用
      • 2.41 Collection接口下的forEach()方法和lambda的梦幻联动
      • 2.42 List接口下的sort()方法和lambda的梦幻联动
  • 4. lambda表达式的优缺点

1. 先回忆一下:

1.1 接口不能直接通过关键字new进行实例化

  1. 接口是引用数据类型,代码中使用interface定义一个接口。接口中的成员变量默认被public static final修饰,接口中的成员方法默认被public abstract修饰,抽象方法没有具体的实现。

  2. 接口中成员方法如果用defaul或者static修饰,该成员方法可以有具体的实现。

    • 接口不能通过new关键字进行实例化:在这里插入图片描述

    • 类通过关键字implement实现接口,类实现接口后,要重写接口中的所有抽象方法。通过实例化(实现了某接口的)类,间接实例化某接口在这里插入图片描述

  3. 接口间可以通过关键字extends进行拓展,即把多个接口合并在一起。在这里插入图片描述

1.2 函数式接口

如果一个接口中有且只有一个抽象方法,那么该接口就是一个函数式接口。在这里插入图片描述

  1. 在写代码时,如果在某个接口上声明了@FunctionalInterface,表示该接口必须是一个函数式接口,否则程序编译会报错。
  2. 下面这种也是函数式接口:
    在这里插入图片描述

1.3 匿名内部类

1.31 匿名内部类在代码中长啥样?

如果一个类定义在类的内部或者方法的内部,该类就是内部类。根据内部类在代码中的位置,内部类可以分为成员内部类和局部内部类。成员内部类与外部类成员所处位置相同,局部内部类定义在方法内部。在这里插入图片描述
匿名内部类和局部内部类一样,都在方法内部,且匿名内部类必须实现接口或者继承其他类。

我们在写代码的时候,如果想在方法内部创建一个类,但是不会用到该类的名字,此时就可以使用匿名内部类。如上述代码中的两个匿名内部类:

  • 第一个匿名内部类的意思是:有一个没有名字的类,该类实现了A接口,并且重写了A接口中的testA方法。在这里插入图片描述

  • 如果用局部内部类实现,代码如下:在这里插入图片描述

  • 第二个匿名内部类的意思是:有一个没有名字的类,该类继承了类B,但没有进行扩展。(一般都要进行扩展,即添加新的成员,否则该匿名内部类无意义)。在这里插入图片描述

  • 如果用局部内部类实现,代码如下:在这里插入图片描述

1.32 构造一个新的对象与构造一个扩展了某类的匿名内部类的对象,两者有什么区别?

如果构造参数列表的,结束小括号后面跟一个开始大括号,就是在定义匿名内部类对象。在这里插入图片描述

1.33 如何调用匿名内部类对象中的成员

在这里插入图片描述

1.34 匿名内部类的变量捕获

在匿名内部类中,不仅能访问外部类的字段,还能访问局部变量。但是无论是字段还是局部变量,都只能是一旦赋值绝不会改变的变量或者被final修饰的常量。

2. lambda表达式

lambda表达式是匿名内部类的简化。说的再详细一点,lambda表达式创建了一个类,实现了一个接口,重写了接口的方法

看下面代码,在代码中对象priorityQueue和对象priorityQueue1完全一样,但是显然,创建priorityQueue1的代码要更加简洁。这是因为创建priorityQueue的时候,构造方法的参数是一个匿名内部类,而创建priorityQueue1的时候,构造方法的参数一个lambda表达式。
所以,使用lambda表达式能让能让代码更加简洁,开发也随之更加迅速,这就是我们学习lambda表达式的原因。
在这里插入图片描述

2.1 语法

lambda表达式的语法: (parameters) -> expression 或 (parameters) ->{ statements; }

  1. parameters是参数,根据实际情况,参数可以有,也可以没有。这里的参数等同于方法的参数列表。
    • 参数的数据类型可以明确声明,也可以不声明而是让JVM推断。如果要省略,每个参数的数据类型都要省略。
    • 当只有一个没有声明类型的参数时,可以省略外面的小括号()。
  2. expression是表达式,是函数式接口里方法的实现。
  3. statements;是代码块,是函数式接口里方法的实现。这里的代码块和表达式等同于方法里面的方法体。
    • 如果方法体中只有一条代码,大括号{}可以省略
    • 如果方法体中只有一条语句,且是return语句,大括号和关键字return可同时省略。

例如:

// 1. 不需要参数,返回值为 2
() -> 2
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的和
(x, y) -> x + y
// 4. 接收2个int型整数,返回他们的乘积
(int x, int y) -> x * y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)

2.2 基本使用

接下来跟着具体场景看看lambda表达式在代码中究竟如何使用:

  1. 已知函数式接口NoParameterNoReturn,接口中的test()方法没有参数,没有返回值。如何调用接口中的test()方法呢?在这里插入图片描述运行结果:
    在这里插入图片描述
  2. 下面是使用lambda表达式的更多例子:
public class Test {
    public static void main1(String[] args) {
        //如何调用接口NoParameterNoReturn中的test方法?
        //不使用lambda表达式(通过匿名内部类实现接口,重写方法):
        NoParameterNoReturn noParameterNoReturn =
                new NoParameterNoReturn() {
            @Override
            public void test() {
                System.out.println("test......");
            }
        };
        noParameterNoReturn.test();
        //使用lambda表达式
        NoParameterNoReturn noParameterNoReturn1 =
                ()-> System.out.println("test......");//重写接口中的方法,该方法没有参数,没有返回值
        noParameterNoReturn1.test();
    }

    public static void main2(String[] args) {
        //如何调用接口OneParameterNoReturn中的test方法?
        OneParameterNoReturn oneParameterNoReturn = (x)->{
            System.out.println(x);
        };//只有一个没声明类型的参数,小括号()可以省略;方法体中只有一条语句,{}可以省略
        oneParameterNoReturn.test(10);

        //如何调用接口MoreParameterNoReturn中的test()方法?test()方法无返回值但是有多个参数
        MoreParameterNoReturn moreParameterNoReturn =
                (int x,int y) -> {
                    System.out.println(x+y);
                };
        moreParameterNoReturn.test(10,20);
    }

    public static void main(String[] args) {
        //如何调用接口NoParameterReturn中的test方法?test方法中有返回值,无参数
        NoParameterReturn noParameterReturn =
                () -> {return 10;};//return和{}可同时省略
        System.out.println(noParameterReturn.test());

        //如何调用接口OneParameterReturn中的test方法?test方法中有返回值,有一个参数
        OneParameterReturn oneParameterReturn = x -> x;
        oneParameterReturn.test(20);//传20返回20
        //如何调用接口MoreParameterReturn中的test方法?test方法中有返回值,有多个参数
        MoreParameterReturn moreParameterReturn =
                (a,b) -> {return a*b;};
        moreParameterReturn.test(10,20);//返回200
    }
}
//无返回值无参数
@FunctionalInterface
interface NoParameterNoReturn {
    void test();
}
//无返回值一个参数
@FunctionalInterface
interface OneParameterNoReturn {
    void test(int a);
}
//无返回值多个参数
@FunctionalInterface
interface MoreParameterNoReturn {
    void test(int a,int b);
}
//有返回值无参数
@FunctionalInterface
interface NoParameterReturn {
    int test();
}
//有返回值一个参数
@FunctionalInterface
interface OneParameterReturn {
    int test(int a);
}
//有返回值多参数
@FunctionalInterface
interface MoreParameterReturn {
    int test(int a,int b);
}

所以如果想在代码中使用lambda表达式,一定要清楚函数式接口中要被重写的方法,该方法中是否有返回值,是否有参数

2.3 lambda的变量捕获

同匿名内部类的变量捕获一样,lambda表达式内不仅能访问外部类的字段,还能访问局部变量。但是无论是字段还是局部变量,都只能是一旦赋值绝不会改变的变量或者被final修饰的常量。

例如在下面代码中:
在这里插入图片描述在多线程编程中,经常会用到lambda表达式,尤其要注意变量捕获这一点,如果在lambda表达式这种用了某变量,但在后续又修改了该变量,代码就会出现问题。

2.4 lambda在集合中的使用

lambda表达式是JavaSE8中的一个重要的新特性。为了能让Lambda和Java的集合类集更好的一起使用,集合当中,也新增了部分接口,以便与Lambda表达式对
接。

对应的接口新增的方法
CollectionremoveIf() spliterator() stream() parallelStream() forEach()
ListreplaceAll() sort()
MapgetOrDefault() forEach() replaceAll() putIfAbsent() remove() replace() computeIfAbsent() computeIfPresent() compute() merge()

接下来会分别演示在Collection接口forEach() 方法中,在List接口sort()方法中,分别如何使用lambda表达式。

其他方法在遇到时,查看Java帮助手册或查看对应源码,同样的方法学习掌握即可。

2.41 Collection接口下的forEach()方法和lambda的梦幻联动

  1. 先找到Collection接口下forEach()方法中的函数式接口:

Collection接口拓展了Iterable接口,在这里插入图片描述

forEach()方法在Iterable接口中,
在这里插入图片描述
forEach()方法的源码如下:从源码中看出,forEach()方法的功能就是遍历当前集合中的元素,然后让每个元素执行action.accept()操作
在这里插入图片描述
forEach()方法的参数action的类型是一个函数式接口,其中的void accept(T t)抽象函数,有一个参数无返回值。
在这里插入图片描述所以当我们调用forEach()方法的时候,forEach()方法的参数是一个函数式接口action,我们需要实现该接口并且重写接口中的accept()的方法。此时我们可以使用匿名内部类或者lambda表达式:

  1. 例如下列代码:

在这里插入图片描述

2.42 List接口下的sort()方法和lambda的梦幻联动

  1. 先找到List接口下sort()方法中涉及的函数式接口:

sort()方法的源码如下:
从源码中看出,sort()方法的功能就是先调用Arrays工具包中的sort方法,并依据比较器c的规则对当前容器元素进行排序。然后再对已经排好序的当前容器进行迭代操作。
在这里插入图片描述
sort方法的参数c的类型是一个函数式接口,其中的int compare(T o1, T o2)抽象函数,有两个参数有返回值。
函数式接口Comparator所以当我们调用sort()方法的时候,sort()方法的参数是一个函数式接口c,我们需要实现该接口并且重写接口中的compare()的方法。此时我们可以使用匿名内部类或者lambda表达式:

2.例如下面代码:
在这里插入图片描述

4. lambda表达式的优缺点

Lambda表达式的优点很明显,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读。

优点:

  1. 代码简洁,开发迅速
  2. 方便函数式编程
  3. 非常容易进行并行计算
  4. Java 引入 Lambda,改善了集合操作

缺点:

  1. 代码可读性变差
  2. 在非并行计算中,很多计算未必有传统的 for 性能要高
  3. 不容易进行调试


好了,本篇到这就结束了,相信读完本篇的你已经能读懂,会用lambda表达式了。最后祝你我早日成为技术流。

我是一朵忽明忽暗的云,点赞收藏加关注,我们一起进步!
在这里插入图片描述

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

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

相关文章

Bert基础(五)--解码器(下)

1、 多头注意力层 下图展示了Transformer模型中的编码器和解码器。我们可以看到,每个解码器中的多头注意力层都有两个输入:一个来自带掩码的多头注意力层,另一个是编码器输出的特征值。 让我们用R来表示编码器输出的特征值,用M来…

visio、ppt、office等另存图片,如何设置更清晰

visio、ppt、office等另存图片,如何设置更清晰 选中要另存为的部分——文件——另存为——选好位置——格式选jpg——保存——按下图设置:质量100%,分辨率选打印机,大小选屏幕——确定

MySQL 教程 2.4

MySQL UNION 操作符 本教程为大家介绍 MySQL UNION 操作符的语法和实例。 描述 MySQL UNION 操作符用于连接两个以上的 SELECT 语句的结果组合到一个结果集合,并去除重复的行。 UNION 操作符必须由两个或多个 SELECT 语句组成,每个 SELECT 语句的列数…

盘点实用又有意思的工具网站-搜嗖工具箱

生命倒计时 www.thismuchlonger.com 这是一个相哇塞的网站,可以让我们静下心来好好想想我们来这个世界究竟为了什么,因为当我们作为命运的主宰者。敲打键盘设定好自己一生长度的时候,我们的剩余寿命已经成绝对值,一旦生命变为了绝…

测试:腾讯云4核8G服务器支持多少人在线访问?

腾讯云4核8G服务器支持多少人在线访问?支持25人同时访问。实际上程序效率不同支持人数在线人数不同,公网带宽也是影响4核8G服务器并发数的一大因素,假设公网带宽太小,流量直接卡在入口,4核8G配置的CPU内存也会造成计算…

【JavaScript 漫游】【028】拖拉事件

文章简介 本篇文章为【JavaScript 漫游】专栏的第 027 篇文章,主要记录了 JavaScript 中拖拉事件的知识点。 拖拉事件的种类 拖拉(drag)指的是,用户在某个对象上按下鼠标键不放,拖动它到另一个位置,然后…

【2024】利用python爬取csdn的博客用于迁移到hexo,hugo,wordpress...

前言 博主根据前两篇博客进行改进和升级 利用python爬取本站的所有博客链接-CSDN博客文章浏览阅读955次,点赞6次,收藏19次。定义一个json配置文件方便管理现在文件只有用户名称,后续可加配置读取用户名称,并且将其拼接成csdn个人博客链接ty…

【python】爬取链家二手房数据做数据分析【附源码】

一、前言、 在数据分析和挖掘领域中,网络爬虫是一种常见的工具,用于从网页上收集数据。本文将介绍如何使用 Python 编写简单的网络爬虫程序,从链家网上海二手房页面获取房屋信息,并将数据保存到 Excel 文件中。 二、效果图&#…

基于springboot+vue的在线考试系统(源码+论文)

文章目录 目录 文章目录 前言 一、功能设计 二、功能页面 三、论文 前言 现在我国关于在线考试系统的发展以及专注于对无纸化考试的完善程度普遍不高,关于对考试的模式还大部分还停留在纸介质使用的基础上,这种教学模式已不能解决现在的时代所产生的考试…

GitLab--Merge Request 权限管理

场景 团队在日常开发工作中需要进行分支管理,通常使用feature分支进行开发,然后依次合并到dev分支、release分支,整个代码合并过程不仅仅是代码合并还需要对代码进行审核,如果在线下进行审核合并,这样操作无法保留痕迹…

博客笔记项目的自动化测试

作者简介:大家好,我是未央; 博客首页:未央.303 系列专栏:测试开发项目 每日一句:人的一生,可以有所作为的时机只有一次,那就是现在!!!! 文章目录 …

idea中springboot项目创建后追加依赖

springboot项目创建后追加依赖 前言1、安装插件editstarters设置->插件 2、进入pom.xml 页面 前言 在项目创建的时候选择好依赖创建项目,之后追加依赖不是很方便,介绍一个简单的使用方法,通过editstarters进行添加 1、安装插件editstart…

Http协议综述

目录 一.B/S架构 二.Http协议 1.概述 2.特点 3.请求数据格式 (1)请求头 (2)请求行 (3)请求体 4.相应数据格式 (1)相应行 (2)相应头 (…

鸡尾酒疗法 T1067

鸡尾酒疗法,原指 “高效抗逆转录病毒治疗”(HAARTHAART),由美籍华裔科学家何大一于 1996 年提出,是通过三种或三种以上的抗病毒药物联合使用来治疗艾滋病。该疗法的应用可以减少单一用药产生的抗药性,最大限…

假如有n个台阶,一次只能上1个台阶或2个台阶,请问走到第n个台阶有几种走法?

说明如下:假如有 3个台阶&#xff0c;那么总计就有3种走法:第一种为每次上1个台阶&#xff0c;上3次;第二种为先上2个台阶&#xff0c;再上1个台阶;第三种为先上1个台阶&#xff0c;再上2个台阶。 解决方法&#xff1a;递归 代码展示&#xff1a; #include <stdio.h> …

chromedriver,Chrome驱动的实时更新

发现自己的selenium项目跑不起来了 效验驱动版本 下载链接(可能需要魔法) https://registry.npmmirror.com/binary.html?pathchromedriver/ https://googlechromelabs.github.io/chrome-for-testing/ 找到驱动位置 1. 默认安装路径&#xff1a;Chrome驱动通常会默认安装在系…

要求将两个链表合并成一个有序(从小到大)链表

给定两个元素有序&#xff08;从小到大&#xff09;的链表&#xff0c;要求将两个链表合并成一个有序&#xff08;从小到大&#xff09;链表&#xff0c; 输入描述: 第一行输入第一个链表的结点数S1&#xff0c;S1<100。 第二行输入S1个整数&#xff0c;两两之间用空格隔开…

Android---SmartRefreshLayout实现上拉刷新和下拉加载更多

1. 在 build.gradle 中添加依赖 // 下拉刷新&#xff0c;上拉加载更多 // https://github.com/scwang90/SmartRefreshLayout implementation io.github.scwang90:refresh-layout-kernel:2.1.0 //核心必须依赖 implementation io.github.scwang90:refresh-header-classics…

CleanMyMac X2024一款专为Mac用户设计的优化工具

亲爱的用户们&#xff0c;我们都知道电脑在长时间使用后会变得越来越慢&#xff0c;垃圾文件和无用的应用程序会占用我们的硬盘空间&#xff0c;让我们的电脑变得像蜗牛一样慢。但是&#xff0c;现在有一个解决方案可以让你的电脑重获新生&#xff0c;那就是CleanMyMac X&#…

笔记本hp6930p安装Android-x86补记

在上一篇日记中&#xff08;笔记本hp6930p安装Android-x86避坑日记-CSDN博客&#xff09;提到hp6930p安装Android-x86-9.0&#xff0c;无法正常启动&#xff0c;本文对此再做尝试&#xff0c;原因是&#xff1a;Android-x86-9.0不支持无线网卡&#xff0c;需要在BIOS中关闭WLAN…