专栏首页疯狂软件李刚一小时掌握方法引用和构造器引用

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

导读

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, ...)

引用类方法

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

@FunctionalInterface

interface Converter{
    Integer convert(String from);
}

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

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

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

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

Integer val = converter1.convert("99");
System.out.println(val); // 输出整数99

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

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

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

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

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

引用特定对象的实例方法

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

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

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

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

Integer value = converter2.convert("it");
System.out.println(value); // 输出2

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

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

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

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

引用某类对象的实例方法

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

@FunctionalInterface
interface MyTest
{
    String test(String a, int b, int c);
}

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

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

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

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

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);,因此可以使用如下方法引用进行替换。

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

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

引用构造器

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

@FunctionalInterface
interface YourTest
{
    JFrame win(String title);
}

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

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

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

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

JFrame jf = yt.win("我的窗口");
System.out.println(jf);

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

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

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

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

本文结束

本文分享自微信公众号 - 疯狂软件李刚(fkbooks),作者:疯狂软件李刚

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-07-20

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 使用Scrapy shell调试一步一步开发爬虫

    很多文章可能直接给你一个爬虫的代码,但这些代码是怎么写出来的,可能往往语焉不详。本文不同,本文并不着重如何写一个爬虫项目,而是一步一步地教会你、一行一行地写出具...

    疯狂软件李刚
  • 关于Python函数装饰器最简单的说明

    本文是关于Python函数装饰器最简单的介绍,没有废话,没有套路,赤裸裸的一句话就掌握Python函数装饰器。

    疯狂软件李刚
  • Python的堆操作,是不是要掌握一下

    Python的强大并不在于它的语法,而在于它的库,当你对各种数据结构感到苦恼时,Python提供了各种开箱即用的数据结构。

    疯狂软件李刚
  • Visual Studio 代码风格约束

    注意,这里的错误是IDE1006:Naming rule violation,编译时依然能通过(没找到在哪里设置不允许通过编译):

    雪飞鸿
  • win10 uwp 获取文件夹出错

    参见:http://stackoverflow.com/a/42969965/6116637

    林德熙
  • 重金挖来台积电研发大牛后,中芯国际三季度营收同比增长10%,达8.51亿美元

    作为中国内地规模最大、技术最先进的集成电路芯片制造企业,中芯国际的发展情况一直备受行业关注。

    镁客网
  • 程序员面试被要求手写代码?你与高级程序员之间的差别就在这里

    在面试中,你被要手写代码,原本自信心爆棚的你突然间提笔忘字。在一张纸上反复涂涂画画,最后勉强的写出了一个功能。结果却漏洞百出。面试过程相当不顺利,丢下笔,敷衍的...

    IT大咖说
  • Java中静态代码块和构造代码块

        构造代码块在创建对象时被调用,每次创建对象都会被调用,并且构造代码块的执行次序优先于类构造函数。

    緣來
  • 如何设计优雅的类结构

    注:正文中的引用是直接引用作者作者的话,两条横线中间的段落的是我自己的观点,其他大约都可以算是笔记了。 「Clean Code」这本书从这一章开始文风有些变化,...

    用户1667431
  • 针对校园某服务器的一次渗透测试

    由于是对内网直接进行大扫描,所以直接判断这不仅是一个 Web 服务器(多个),同时还运行着 FTP、数据库。

    HACK学习

扫码关注云+社区

领取腾讯云代金券