由浅入深学习lambda表达式

前言

lambda表达式采用的是一种简洁的语法,来传递代码块。使得java能够支持函数式编程。

问题引入

我们先来看一个简单的java API:

Arrays.sort(T[] a, Comparator<? super T> c)

其中,a是待排序数组,c是一个实现了Comparator接口的比较器对象。
在没有lambda表达式之前,我们需要自己创建一个类并实现Comparator接口的compare方法,并在调用Arrays.sort时传入我们所创建的这个比较器的对象。
如:

class LengthComparator implements Comparator<String>
{
	public int compare(String first, String second)
	{
		return first.length() - second.length();
	}
}
... ...
String[] strings = new String[]{"aaa", "bbb", "ccc"};
Arrays.sort(strings, new LengthComparator());

这样做的目的仅仅是为了让sort方法能够在排序时调用我们自定义的compare方法,显然上述方法是很麻烦且不够优雅的。

于是,lambda表达式这个新特性应运而生,它的作用,便是直接传递一个代码块

lambda表达式的语法

参数表 -> {代码体}
例如:(String s1, String s2)-> {return s1.length() - s2.length()}

  • 当lambda表达式不需要传参时,你仍需要提供一个空括号,例如:
() -> {'hello lambda'}
  • 如果能够从上下文推导出参数类型,可省去参数类型,例如:
(s1, s2) -> {s1.length() - s2.length()}
  • 如果参数表仅有一个参数,且这个参数的类型也可以推导出来,那么可以直接省去括号和类型
s -> {s.length()}
  • 有时甚至可以省略掉return语句,lambda表达式的返回值可以从上下文中推导得出
e -> {e == null}

lambda表达式的存储

对于任何类型,我们都可以声明一个变量来存储它的值,那么我们该用什么类型的变量来存储lambda表达式这样一个代码块呢。

java的设计者并没有选择像其他类型的编程语言一样,增加函数类型,而是仍然采用接口类型,来存储lambda表达式。这个特殊的接口叫做函数式接口
**
这个函数式接口必须
有且仅有**一个抽象方法(可有其他静态方法,默认方法),该方法的返回值即为lambda表达式的返回值,该方法的参数表即为lambda表达式的参数表,
换句话说,lambda表达式便可以看作这个抽象方法的实现。

注意,lambda表达式只能赋给函数式接口,甚至不能将它赋给Object类

于是,当我们想给某个方法传入一个代码块时,只需要保证该方法有着与你想要传入的lambda表达式相匹配的函数式接口类型的参数即可。

让我们再回到开头的那个例子:

Arrays.sort(T[] a, Comparator<? super T> c)

现在我们调用这个sort方法,不必再像之前那样繁琐,直接可以这样:

String[] strings = new String[]{"aaa", "bbb", "ccc"};
Arrays.sort(strings, (first, second) -> 
{first.length() - second.length()});

方法引用 (Method Reference)

如果你的lambda表达式仅仅是调用另外一个另外一个方法,那么你可以传入一个方法引用而不是lambda表达式
示例:

//创建一个定时器,周期性打印事件对象
var time = new Timer(1000, System.out::println)

需要注意的是,传入的方法引用的参数表要与该函数式接口的抽象方法的参数表一致

运算符 :: 分隔对象名(类名)和方法名。有以下三种情况:

  1. 对象 :: 实例方法
  2. 类 :: 实例方法
  3. 类 :: 静态方法

特别指出对于第二种情况,该函数式接口的抽象方法中,第一个参数的类型必须是方法引用中的那个类

闭包

先看这样一个例子:

public static void repeatMessage(String text, int delay)
{
	ActionListener listener = event -> {
		System.out.print(text);
	}
}

其中,lambda表达式的代码块内部使用了代码块外部的自由变量
这里我们先介绍以下lambda表达式的组成:

  1. 一个代码块({}中的内容)
  2. 参数表
  3. 自由变量的值 (即不是代码块中声明的变量,也不是参数表中的变量,而是外部的变量)

当外部变量,也就是自由变量,被lambda表达式所使用后,它的值便不允许改变,也就是说这个变量从变量变成常量了

关于代码块以及自由变量有一个术语叫做闭包,不仅仅是python有闭包,java也有闭包

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本课程名为《由浅入深Java》,是专门面向零基础学员量身打造的一门课程!其目的是帮助有志于成为Java工程师的学员迈出实现理想的第一步--跨过Java语法这个门槛。课程共有三个板块,分别是《零基础学Java》、《零基础学Java习题精讲》和《Java高级语法》。《零基础学Java》的目标是带领零基础的学员学会Java语言的最基本语法,达到快速入门的目的。该课程主要讲解Java基本常识、Java基础语法、面向对象思想及相关语法细节,以及异常的概念和处理方法。学员掌握了基础语法之后,紧接着做的事情就是夯实理论基础以及提高实战能力。第二板块《零基础学Java习题精讲》就是为此目标而精心设计的。该课程分为两部分,分别是《选择问答篇》和《编程篇》。《选择问答篇》中精选了很多有代表性的题目,帮助学员进一步理解Java语法细节,并扫除那些掌握不扎实的知识漏洞。《编程篇》则精选了几十个经典编程题,帮助学员提升逻辑思维能力和解决问题的实战能力!掌握了Java基础语法之后,还要继续提升战斗力!第三板块《Java高级语法》已经来到了你的面前!这门课程是Java语法的进阶课程。主要讲解Java语言的高级语法:如位运算符、内部类、泛型、Lambda表达式等知识点。认真学习完本专题的三门课程,你的Java语法就能达到过关的水平,后续在学习Java API、Java WEB、Android开发、第三方框架的使用等高级课程的时候,你将不会再有“语法”问题!整个课程选用当前行业中使用最广泛的Java17为开发环境进行讲解。效果好不好,学了就知道! 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值