Java 构造函数引用,用户希望将方法引用作为流的流水线(stream pipeline)的一部分,以实例化某个对象。在方法引用中使用 new
关键字。
Java 构造函数引用 问题描述
用户希望将方法引用作为流的流水线(stream pipeline)的一部分,以实例化某个对象。
Java 构造函数引用 解决方案
在方法引用中使用 new
关键字。
Java 构造函数引用 具体实例
在讨论 Java 8 引入的新语法时,通常会提及 lambda 表达式、方法引用以及流。例如,我们希望将一份人员列表转换为相应的姓名列表。例 1-13 的代码段显示了解决这个问题的两种方案。
例 1-13 将人员列表转换为姓名列表
❶ lambda 表达式
❷ 方法引用
那么,是否存在其他解决方案呢?如何根据字符串列表来创建相应的 Person
引用列表呢?尽管仍然可以使用方法引用,不过这次我们改用关键字 new
,这种语法称为构造函数引用(constructor reference)。
为了说明构造函数引用的用法,我们首先创建一个 Person
类,它是最简单的 Java 对象(POJO)。Person
类的唯一作用是包装一个名为 name
的简单字符串特性,如例 1-14 所示。
例 1-14
Person
类
如例 1-15 所示,给定一个字符串集合,通过 lambda 表达式或构造函数引用,可以将其中的每个字符串映射到 Person
类。
例 1-15 将字符串转换为
Person
实例
❶ 使用 lambda 表达式来调用构造函数
❷ 使用构造函数引用来实例化 Person
Person::new
的作用是引用 Person
类中的构造函数。与所有 lambda 表达式类似,由上下文决定执行哪个构造函数。由于上下文提供了一个字符串,使用单参数的 String
构造函数。
1.复制构造函数
复制构造函数(copy constructor)传入一个 Person
参数,并返回一个具有相同特性的新 Person
,如例 1-16 所示。
例 1-16
Person
的复制构造函数
如果需要将流代码从原始实例中分离出来,复制构造函数将很有用。假设我们有一个人员列表,先将其转换为流,再转换回列表,那么引用不会发生变化,如例 1-17 所示。
例 1-17 将列表转换为流,再转换回列表
❶ 对象相同
❷ 使用 before
引用修改人名
❸ after
引用中的人名已被修改
如例 1-18 所示,可以通过复制构造函数来切断连接。
例 1-18 使用复制构造函数
❶ 使用复制构造函数
❷ 对象不同
❸ 但二者是等效的
可以看到,当调用 map
方法时,上下文是 Person
实例的流。因此,Person::new
调用构造函数,它传入一个 Person
实例并返回一个等效的新实例,同时切断了 before
和 after
引用之间的连接。
2.可变参数构造函数
接下来,我们为 Person
POJO 添加一个可变参数构造函数(varargs constructor),如例 1-19 所示。
例 1-19 构造函数
Person
传入String
的可变参数列表
上述构造函数传入零个或多个字符串参数,并使用空格作为定界符将这些参数拼接在一起。
那么,如何调用这个构造函数呢?任何传入零个或多个字符串参数(由逗号隔开)的客户端都会调用这个构造函数。一种方案是利用 String
类定义的 split
方法,它传入一个定界符并返回一个 String
数组。
因此,例 1-20 中的代码将列表中的每个字符串拆分为单个单词,并调用可变参数构造函数。
例 1-20 可变参数构造函数的应用
❶ 创建字符串流
❷ 映射到字符串数组流
❸ 映射到 Person
流
❹ 收集到 Person
列表
在本例中,map
方法的上下文包含 Person::new
构造函数引用,它是一个字符串数组流,因此将调用可变参数构造函数。如果为该构造函数添加一个简单的打印语句:
则输出如下结果:
3.数组
构造函数引用也可以和数组一起使用。如果希望采用 Person
实例的数组(Person[]
)而非列表,可以使用 Stream
接口定义的 toArray
方法,它的签名为:
toArray
方法采用 A
表示返回数组的泛型类型(generic type)。数组包含流的元素,由所提供的 generator
函数创建。我们甚至还能使用构造函数引用,如例 1-21 所示。
例 1-21 创建
Person
引用的数组
❶ Person
的构造函数引用
❷ Person
数组的构造函数引用
toArray
方法参数创建了一个大小合适的 Person
引用数组,并采用经过实例化的 Person
实例进行填充。
构造函数引用其实是方法引用的别称,通过关键字 new
调用构造函数。同样,由上下文决定调用哪个构造函数。在处理流时,构造函数引用可以提供很大的灵活性。
需要说明的是,将葛丽丝 • 霍普(Grace Hopper)将军作为本书代码中的“对象”绝无冒犯之意。作者深信,尽管霍普将军已于 1992 年去世,她的水平仍然是作者所无法企及的。(葛丽丝 • 霍普是美国海军准将,也是全球最早的程序员之一。霍普开发了 COBOL 语言,被誉为“COBOL 之母”,计算机术语 bug 和 debug 也是由霍普团队首先使用并流传开来的。——译者注)