匿名内部类、lambda和方法引用其实是相通的,从匿名内部类到lambda到方法引用是一个进化的过程,是一个简化的过程,更加是一个从抽象的过程。
作用都是实现接口方法,换句话说就是实现接口;只是这个接口只有一个抽象方法。
匿名内部类
省去了实现类,直接new 接口名(){...} 没有实现类名,实际就是实现且创建了一个接口对象。
- 匿名内部类也就是没有名字的内部类
- 正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写
- 但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口
匿名内部类由于没有名字,所以它的创建方式有点儿奇怪。创建格式如下:
new 父类构造器(参数列表)|实现接口() { //匿名内部类的类体部分 }
- 在这里我们看到使用匿名内部类我们必须要继承一个父类或者实现一个接口,当然也仅能只继承一个父类或者实现一个接口。同时它也是没有class关键字,这是因为匿名内部类是直接使用new来生成一个对象的引用。当然这个引用是隐式的。
Lambda表达式
省去了new 接口名;简化为() ->{...} 实际也是实现且创建一个接口对象。
一个方法的参数,括号中是否可以使用Lambda表达式,取决于这个方法的参数类型:
----是否是一个函数式接口(只有一个抽象方法可以有多个default方法的接口),构造方法也同理。
我们可以将lambda表达式定义为一种 简洁、可传递的匿名函数,
首先我们需要明确lambda表达式本质上是一个函数,虽然它不属于某个特定的类,但具备参数列表、函数主体、返回类型,以及能够抛出异常;
其次它是匿名的,lambda表达式没有具体的函数名称;lambda表达式可以像参数一样进行传递,从而极大的简化代码的编写。格式定义如下:
格式一: 参数列表 -> 表达式 格式二: 参数列表 -> {表达式集合}
需要注意的是:
- lambda表达式隐含了return关键字,所以在单个的表达式中,我们无需显式的写return关键字,
- 但是当表达式是一个语句集合的时候,则需要显式添加return,并用花括号
{ }
将多个表达式包围起来,下面看几个例子:
//返回给定字符串的长度,隐含return语句
(String s) -> ()
// 始终返回42的无参方法
() -> 42
// 包含多行表达式,则用花括号括起来
(int x, int y) -> {
int z = x * y;
return x + z;
}
方法引用
省去了lambda,将接口方法实现的内容封装到具体方法,将方法作为接口实现,实际也是实现且创建一个接口对象。
只是更加抽象,只能看到接口方法内部实现(调用的这个方法就是具体实现)。
采用方法引用可以更近一步的简化代码,有时候这种简化让代码看上去更加的直观,先看一个例子:
/* ... 省略apples的初始化操作 */
// 采用lambda表达式
((Apple a, Apple b) -> ((), ()));
// 采用方法引用
((Apple::getWeight));
方法引用通过::
将方法隶属和方法自身连接起来,主要分为三类:
静态方法
(args) -> (args) 转换成 ClassName::staticMethod
参数的实例方法
(args) -> () 转换成 ClassName::instanceMethod // ClassName是args的类型
外部的实例方法
(args) -> (args) 转换成 ext::instanceMethod(args)