前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一小时掌握方法引用和构造器引用

一小时掌握方法引用和构造器引用

作者头像
疯狂软件李刚
发布2020-06-24 17:11:18
8740
发布2020-06-24 17:11:18
举报
文章被收录于专栏:疯狂软件李刚疯狂软件李刚

导读

Java Lambda表达式是很常用的语法,Lambda表达式进一步简化就可写成方法引用和构造器引用。

如果Lambda表达式的代码块只有一条代码,程序就可以省略Lambda表达式中代码块的花括号。不仅如此,如果Lambda表达式的代码块只有一条代码,还可以在代码块中使用方法引用和构造器引用。

提示

方法引用和构造器引用的本质就是为了省略形参列表,有些编程语言为了省略Lambda表达式的形参列表,允许使用1、2这种形式代替第一个、第二个参数,但Java的Lambda表达式的简化还不够彻底,因此只能用方法引用、构造器引用来省略形参列表!

让我们一起期望Java新版本的Lambda表达式简化得更加彻底吧

方法引用和构造器引用可以让Lambda表达式的代码块更加简洁。方法引用和构造器引用都需要使用两个英文冒号。Lambda表达式支持如表1所示的几种引用方式。

表1 Lambda表达式支持的方法引用和构造器引用

种 类

示 例

说 明

对应的Lambda表达式

引用类方法

类名::类方法

函数式接口中被实现方法的全部参数传给该类方法作为参数

(a,b,...) -> 类名.类方法(a,b, ...)

引用特定对象的实例方法

特定对象::实例方法

函数式接口中被实现方法的全部参数传给该方法作为参数

(a,b, ...) -> 特定对象.实例方法(a,b, ...)

引用某类对象的实例方法

类名::实例方法

函数式接口中被实现方法的第一个参数作为调用者,后面的参数全部传给该方法作为参数

(a,b, ...) ->a.实例方法(b, ...)

引用构造器

类名::new

函数式接口中被实现方法的全部参数传给该构造器作为参数

(a,b, ...) ->new 类名(a,b, ...)

引用类方法

先看第一种方法引用:引用类方法。例如,定义了如下函数式接口。

代码语言:javascript
复制
@FunctionalInterface

interface Converter{
    Integer convert(String from);
}

该函数式接口中包含一个convert()抽象方法,该方法负责将String参数转换为Integer。下面代码使用Lambda表达式来创建一个Converter对象(程序清单同上)。

代码语言:javascript
复制
// 下面代码使用Lambda表达式创建Converter对象
Converter converter1 = from -> Integer.valueOf(from);

上面Lambda表达式的代码块只有一条语句,因此程序省略了该代码块的花括号;而且由于表达式所实现的convert()方法需要返回值,因此Lambda表达式将会把这条代码的值作为返回值。

接下来程序就可以调用converter1对象的convert()方法将字符串转换为整数了,例如如下代码:

代码语言:javascript
复制
Integer val = converter1.convert("99");
System.out.println(val); // 输出整数99

上面代码调用converter1对象的convert()方法时——由于converter1对象是Lambda表达式创建的,convert()方法执行体就是Lambda表达式的代码块部分,因此上面程序输出99。

上面Lambda表达式的代码块只有一行调用类方法的代码,因此可以使用如下方法引用进行替换(程序清单同上)。

代码语言:javascript
复制
// 方法引用代替Lambda表达式:引用类方法
// 函数式接口中被实现方法的全部参数传给该类方法作为参数
Converter converter1 = Integer::valueOf;

对于上面的类方法引用,也就是调用Integer类的valueOf()类方法来实现Converter函数式接口中唯一的抽象方法,当调用Converter接口中的唯一的抽象方法时,调用参数将会传给Integer类的valueOf()类方法。

正如前面所说的,Lambda表达式的方法引用就是为了省略形参列表——由于省略形参列表之后,无法在代码中引用任何参数,因此Java的Lambda表达式会自动将所有参数传入指定类的类方法。

引用特定对象的实例方法

下面看第二种方法引用:引用特定对象的实例方法。先使用Lambda表达式来创建一个Converter对象

代码语言:javascript
复制
// 下面代码使用Lambda表达式创建Converter对象
Converter converter2 = from -> "fkit.org".indexOf(from);

上面Lambda表达式的代码块只有一条语句,因此程序省略了该代码块的花括号;而且由于表达式所实现的convert()方法需要返回值,因此Lambda表达式将会把这条代码的值作为返回值。

接下来程序就可以调用converter1对象的convert()方法将字符串转换为整数了,例如如下代码(程序清单同上):

代码语言:javascript
复制
Integer value = converter2.convert("it");
System.out.println(value); // 输出2

上面代码调用converter1对象的convert()方法时——由于converter1对象是Lambda表达式创建的, convert()方法执行体就是Lambda表达式的代码块部分,因此上面程序输出2。

上面Lambda表达式的代码块只有一行调用"fkit.org"的indexOf()实例方法的代码,因此可以使用如下方法引用进行替换:

代码语言:javascript
复制
// 方法引用代替Lambda表达式:引用特定对象的实例方法
// 函数式接口中被实现方法的全部参数传给该方法作为参数
Converter converter2 = "fkit.org"::indexOf;

对于上面的实例方法引用,也就是调用"fkit.org"对象的indexOf()实例方法来实现Converter函数式接口中唯一的抽象方法,当调用Converter接口中的唯一的抽象方法时,调用参数将会传给"fkit.org"对象的indexOf()实例方法。

引用某类对象的实例方法

下面看第三种方法引用:引用某类对象的实例方法。例如,定义了如下函数式接口。

代码语言:javascript
复制
@FunctionalInterface
interface MyTest
{
    String test(String a, int b, int c);
}

该函数式接口中包含一个test()抽象方法,该方法负责根据String、int、int三个参数生成一个String返回值。下面代码使用Lambda表达式来创建一个MyTest对象:

代码语言:javascript
复制
// 下面代码使用Lambda表达式创建MyTest对象
MyTest mt = (a, b, c) -> a.substring(b, c);

上面Lambda表达式的代码块只有一条语句,因此程序省略了该代码块的花括号;而且由于表达式所实现的test()方法需要返回值,因此Lambda表达式将会把这条代码的值作为返回值。

接下来程序就可以调用mt对象的test()方法了,例如如下代码(程序清单同上):

代码语言:javascript
复制
String str = mt.test("Java I Love you", 2, 9);
System.out.println(str); // 输出:va I Lo

上面代码调用mt对象的test()方法时——由于mt对象是Lambda表达式创建的,test()方法执行体就是Lambda表达式的代码块部分,因此上面程序输出va I Lo。

上面Lambda表达式的代码块只有一行a.substring(b, c);,因此可以使用如下方法引用进行替换。

代码语言:javascript
复制
// 方法引用代替Lambda表达式:引用某类对象的实例方法
// 函数式接口中被实现方法的第一个参数作为调用者
// 后面的参数全部传给该方法作为参数
MyTest mt = String::substring;

对于上面的实例方法引用,也就是调用某个String对象的substring()实例方法来实现MyTest函数式接口中唯一的抽象方法,当调用MyTest接口中的唯一的抽象方法时,第一个调用参数将作为substring()方法的调用者,剩下的调用参数会作为substring()实例方法的调用参数。

引用构造器

下面看构造器引用。例如,定义了如下函数式接口(程序清单同上)。

代码语言:javascript
复制
@FunctionalInterface
interface YourTest
{
    JFrame win(String title);
}

该函数式接口中包含一个win()抽象方法,该方法负责根据String参数生成一个JFrame返回值。下面代码使用Lambda表达式来创建一个YourTest对象(程序清单同上)。

代码语言:javascript
复制
// 下面代码使用Lambda表达式创建YourTest对象
YourTest yt = a -> new JFrame(a);

上面Lambda表达式的代码块只有一条语句,因此程序省略了该代码块的花括号;而且由于表达式所实现的win()方法需要返回值,因此Lambda表达式将会把这条代码的值作为返回值。

接下来程序就可以调用yt对象的win()方法了,例如如下代码(程序清单同上):

代码语言:javascript
复制
JFrame jf = yt.win("我的窗口");
System.out.println(jf);

上面代码调用yt对象的win()方法时——由于yt对象是Lambda表达式创建的,因此win()方法执行体就是Lambda表达式的代码块部分,即执行体就是执行new JFrame(a);语句,并将这条语句的值作为方法的返回值。

上面Lambda表达式的代码块只有一行new JFrame(a);,因此可以使用如下构造器引用进行替换(程序清单同上)。

代码语言:javascript
复制
// 构造器引用代替Lambda表达式
// 函数式接口中被实现方法的全部参数传给该构造器作为参数
YourTest yt = JFrame::new;

对于上面的构造器引用,也就是调用某个JFrame类的构造器来实现YourTest函数式接口中唯一的抽象方法,当调用YourTest接口中的唯一的抽象方法时,调用参数将会传给JFrame构造器。从上面程序中可以看出,调用YourTest对象的win()抽象方法时,实际只传入了一个String类型的参数,这个String类型的参数会被传给JFrame构造器——这就确定了是调用JFrame类的、带一个String参数的构造器。

本文结束

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-07-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 疯狂软件李刚 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档