Lambda表达式 函数式接口 到底谁是谁

jdk8 搞了一个很大的语法更新。其中之一就是Lambda表达式。当然还有函数式接口这样的东西。说实话。刚开始内心是拒绝学习的。因为这么写很多时候你dubug的时候感觉很很无助。当然慢慢习惯的就好。但是到现在我对这两个概念还是模糊的。谁是谁的问题。我现在还没搞清楚。只能是先记录下来。当成学习笔记了。先看Lambda表达式

我先讲Lambda表达式长什么样子。在我看来就是一个所谓的匿名函数。 就是左边 中间 右边。三部分。中间比较简单就是箭头号 ->。这个箭头估计用来做语法解析的时候好识别。 然后左边 我们可以理解成是函数的入参。右边我们可以理解成函数的实现。左边我们先看看看各种写法。

第一种 就是一个括号 ()。这里我们可以类似理解成一个函数没有入参。
第二种 就是括号里头有参数 ,但是参数没有类型定义 (x) (x,y,z) 这种比较诡异,说实话习惯了每个变量都有类型定义的人看这种代码是崩溃的。
第三种 是大家习惯的括号内有参数。而且参数是有类型定义的。(String x,int a) (Long s,Date a)
第四种。更让你崩溃的。没有括号 ,就是纯的变量 x x,y 。个人觉得搞成这么颠覆写法真的好嘛。

然后我们看右边。右边可以理解成函数的实现。也有各种情况。先说函数实现部分的范围。
第一种就是传统的有花括号的{},这种都是函数实现超过了一行语句。
第二种就是花括号也没有了。这种就是说明函数就只有一行语句。

再分函数有返回值跟没有返回值。没有返回值就不说了。正常写。有返回值。之前写函数。有返回值就必须有 return这个关键字。但是Lambda表达式里头单语句的时候可以不写return。比如 (String s)->s.indexOf(‘a’) 就表示入参是一个String,返回值是一个int值。

当然作为函数体。里头是可以定义自己局部变量,也可以引用函数体外面的变量。对照以前匿名函数,如果方法体里头要用外面的变量。这个变量必须显示定义final类型。但是Lambda表达式里头不用强势要求定义final。但是这个变量必须遵循final变量的原则。基础类型不能变。引用类型地址不能改。说到底还是final。只不过让你少写一个final而已。。

方法体里头还有一种特殊的关键字 this。再讲this之前。其实我一直是有个疑问的。就是Lambda表达式理解是匿名函数,但是我们传统观念里头。一切的源头都是类啊。当初弄出来一个Lambda表达式。这个表达式整体表示的是啥。其实既然能用this。就说明她整体其实是一个类的实例。这个实例是一个实现了某个接口的匿名类的实例。匿名函数的本身就是对这个接口定义方法的实现。如果按照这个说法 this就应该是这个匿名类才对啊。但是很奇特。这个this恰恰不是这个匿名类。而是这个Lambda表达式所在类。为了验证这个。我写了一段代码。
在这里插入图片描述
从执行结果也印证了this的所指。哪到底这个Lambda表达式 的整体到底是不是一个实现了接口的匿名类的实例呢。我们接着往下看 函数式接口。 这个也是新特性。先看定义
函数式接口(Functional Interface)就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。

这里还有一个新的注解。@FunctionalInterface 从名字翻译来看就知道函数式接口这个概念的来源。
这里有几个地方要注意。首先是抽象方法必须有且只有一个。现在接口里头可以有自己默认实现。当然这个默认实现要加default关键字。一看就知道不是抽象方法可以排除。下面是一个典型的定义

在这里插入图片描述

那正常来这个接口实现。一般来说要定义一个class implements.然后把sayMessage方法补充完整。但是我们现在有了Lambda表达式。我们可以这样。
在这里插入图片描述
看到没有。首先 sayMessage这个方法名没了。因为Lambda表达式的核心是匿名函数。 也就是没有方法名。message ->System.out.print(“hello”);这个部分正好是是对上面这个接口的实现形式。 看到这里是不是感觉我之前的判断ok。Lambda表达式就是一个实现接口的匿名类的实例。如果这个判断成立。要完成这种Lambda表达式表达就要定义很很多的这种函数接口才行。果然java就是好人。这种通用接口全都给你定义好了。都在哪里呢。这里分成两部分。第一部分就是原来的已经符合函数式接口定义的一些接口。第二部分就是新定义出来的一些接口。我们先说原来有的。

Runnable
在这里插入图片描述
一个抽象方法。没有任何返回参数。以后可以这么写
new Thread( () -> System.out.println(“In Java8, Lambda expression”) ).start();

()->System.out.println(“In Java8, Lambda expression”) 就是一个实现了Runnable接口的匿名类实例。

Callable
在这里插入图片描述
这个跟runnable区别就是 有返回值。V代表了返回值的类型。
Callable c2 = true ? (() -> 42) : (() -> 24);
System.out.println(c2.call());

这段代码 ()->42 就是一个实现了Callable的匿名类。同理()->24也是。

这两个接口正好印证之前 说 Lambda表达式 的没有入参 ,没有返回结果跟有返回结果的情况。原来都是背后有函数式接口对应的。也就是说所有Lambda表达式的背后都是有定义好的函数式接口的定义。这两个都比较简单。下面看一个复杂的
在这里插入图片描述
在这里插入图片描述
这里有两个抽象方法。 compare(T,T) equals(Object) 这里居然有两个。照理不应该不属于函数式接口么。但是equals是属于Object的类。其实任何类都已经有实现。所以真的抽象方法就只有一个。其余的比如comparing 还有thenComparing方法都是具体实现的方法。comparing 的参数里头这些什么Function ToIntFunction 其实也是函数式接口。后面会提到。
当然说到这里 就要说类似的一个接口 Comparable。 基本类似。唯一的抽象方法的参数个数是不一样的。我贴出来大家就理解了
在这里插入图片描述
在这里插入图片描述
很明显Comparable 是跟自己比较的。当然返回值都是int

最后我们来看看java为我们写lamadb代码方便。提前定义好的几个常用的函数接口 。这些所有的新定义的接口都在java.util.function下面。大概几十个。这里只介绍常用的 几个

1.Supplier函数式接口-用来做生产的
在这里插入图片描述
没有入参。但是有返回值。
2对应的是有入参。没有返回值的Consumer
在这里插入图片描述
3当然还有一个入参。一个返回值的Function
在这里插入图片描述
最后是一个入参。返回值就是Boolean。
在这里插入图片描述
其余的基本的就是多个入参或者指名入参类型的这四种基本类型的延申。比BiConsumer就是两个参数。DoubleConsumer 就是入参是double型。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值