JDK 8 见证了一个特殊特性的出现:构造函数引用和方法引用。在本文中, Adrian D. Finlay 探讨了开发人员如何释放构造函数引用的真正潜力。
如果你还不知道 Java 构造函数本身就是特殊的方法,那么阅读方法引用的基本示例将对读者有所帮助,通过了解这些内容,可以了解构造函数引用是什么。
「方法引用为已经有名称的方法提供易读的 lambda 表达式。」
「它们提供了一种无需执行就可以引用方法的简单方式。」
以上引自《Java 8 编程参考官方教程(第 9 版)》,作者:Herbert Schildt
译注:该书的第 8 版中文译本名称为:《Java 完全参考手册(第 8 版)》,第 9 版中文译本名称为:《Java 8 编程参考官方教程(第 9 版)》
方法引用可以引用静态方法和实例方法,两者是通用的。方法引用是函数式接口的实例。虽然 Lambda 表达式允许你动态创建方法实现,但通常情况下,一个方法最终会调用 Lambda 表达式中的另一个方法来完成我们想要完成的工作。更直接的方法是使用方法引用。当你已经有一个方法来实现这个函数式接口时,这是非常有用的。
让我们看一个使用静态方法及实例方法的示例。
//step #1 - Create a funnctional interface. interface FuncInt { //contains one and only abstract method String answer(String x, boolean y); } //step #2 - Class providing method(s)that match FuncInt.answer()'s definition. class Answer { static String ans_math_static(String x, Boolean y) { return "/"" + x + "/"" + "/t = /t" + y.toString().toUpperCase(); } String ans_math_inst(String x, Boolean y) { return "/"" + x + "/"" + "/t = /t" + y.toString().toUpperCase(); } }
译注:以上代码的测试用例如下,因静态方法与实例方法结果相同,仅以静态方法为例。
Answer.ans_math_static("9 > 11 ?", false); Answer.ans_math_static("987.6 < 1.1 ?", false); Answer.ans_math_static("1 > 0.9 ?", true); Answer.ans_math_static("T/F: Is Chengdu in Sichuan?", true); Answer.ans_math_static("-1 % 0.2=0 ?", false); Answer.ans_math_static("T/F: Does Dwyne Wade play for the Knicks?", false);
得到与原文举例相同的输出结果:
"9 > 11 ?" = FALSE "987.6 < 1.1 ?" = FALSE "1 > 0.9 ?" = TRUE "T/F: Is Chengdu in Sichuan?" = TRUE "-1 % 0.2=0 ?" = FALSE "T/F: Does Dwyne Wade play for the Knicks?" = FALSE
另请参阅: 关于var的所有内容:局部变量类型推断如何清除Java代码冗余
使用方法引用的主要步骤有:
类名 :: 方法名
;实例方法的方法引用格式为 对象实例名 :: 方法名
。
Instance.AbstractMethod();
这提供了一种创建方法实现的可插拔方式。Lambda 表达式和方法引用为 Java 编程带来了一个功能方面的提升。
另请参阅: 你到底有多了解Java的注解?
让我们开始详细讨论吧。
构造函数和其他方法一样是方法。对吗?错。它们有点特殊,它们是对象初始化方法。尽管如此,它们仍然是一个方法,没有什么能阻止我们像其他方法引用一样创建构造函数的方法引用。
//step #1 - Create a funnctional interface. interface FuncInt { //contains one and only abstract method Automobile auto(String make, String model, short year); } //step #2 - Class providing method(s)that match FuncInt.answer()'s definition. class Automobile { //Trunk Member Variables private String make; private String model; private short year; //Automobile Constructor public Automobile(String make, String model, short year) { this.make = make; this.model = model; this.year = year; } protected void what() { System.out.println("This Automobile is a" + year + " " + make + " " + model + "."); } } //Step #3 - Class making use of method reference public class ConstrRef { static void createInstance() { } public static void main(String[] args) { System.out.println(); //Remember, a Method Reference is an instance of a Functional Interface. Therefore.... FuncInt auto = Automobile::new;//We really don't gain much from this example //Example #1 Automobile honda = auto.auto("honda", "Accord", (short) 2006); honda.what(); //Example #1 Automobile bmw = auto.auto("BMW", "530i", (short) 2006); bmw.what(); System.out.println(); } }
输出结果
This Automobile is a2006 honda Accord. This Automobile is a2006 BMW 530i.
用户应该清楚的第一件事是这个基本示例没有那么实用。这是一种相当迂回的创建对象实例的方式。实际上,几乎可以肯定,你不会经历所有这些麻烦来创建一个 Automobile 实例,但是为了概念的完整性,还是要提及。
使用构造函数的方法引用的主要步骤有:
类名 :: new
MyClass x = ConstructorReference.AbstractMethod (x, y, z…)
构造函数引用与泛型一起使用的时候变得更有用。通过使用泛型工厂方法,可以创建各种类型的对象。
让我们看一看。
//step #1 - Create a funnctional interface. interface FuncInt<Ob, X, Y, Z> { //contains one and only abstract method Ob func(X make, Y model, Z year); } //step #2 - Create a Generic class providing a constructor compatible with FunInt.func()'s definition class Automobile<X, Y, Z> { //Automobile Member Variables private X make; private Y model; private Z year; //Automobile Constructor public Automobile(X make, Y model, Z year) { this.make = make; this.model = model; this.year = year; } protected void what() { System.out.println("This Automobile is a " + year + " " + make + " " + model + "."); } } //step #3 - Create a Non-Generic class providing a constructor compatible with FunInt.func()'s definition class Plane { //Automobile Member Variables private String make; private String model; private int year; //Plane Constructor public Plane(String make, String model, int year) { this.make = make; this.model = model; this.year = year;//Automatic unboxing } protected void what() { System.out.println("This Plane is a " + year + " " + make + " " + model + "."); } } //Step #3 - Class making use of method reference with generics public class ConstrRefGen { //Here is where the magic happens static <Ob, X, Y, Z> Ob factory(FuncInt<Ob, X, Y, Z> obj, X p1, Y p2, Z p3) { return obj.func(p1, p2, p3); } public static void main(String[] args) { System.out.println(); //Example #1 FuncInt<Automobile<String, String, Integer>, String, String, Integer> auto_cons = Automobile<String, String, Integer>::new; Automobile<String, String, Integer> honda = factory(auto_cons, "Honda", "Accord", 2006); honda.what(); //Example #2 FuncInt<Plane, String, String, Integer> plane_cons = Plane::new; Plane cessna = factory(plane_cons, "Cessna", "Skyhawk", 172); cessna.what(); System.out.println(); } }
输出结果
This Automobile is a 2006 Honda Accord. This Plane is a 172 Cessna Skyhawk.
另请参阅: Java 中的 struct :如何像专业人士一样处理它们
这里有很多东西需要消化。事实上,如果你以前从未深入研究过泛型,那么这些代码看上去可能相当晦涩。让我们分解一下。
我们做的第一件事是创建一个通用的函数式接口。注意细节。我们有四个泛型类型参数:Ob、X、Y、Z。
如果我们替换泛型方法占位符,抽象方法可能是这样的: SomeClass func (String make, String model, int year)
。注意,由于我们使接口具有了泛型,所以可以指定任何返回类型或我们希望返回的类实例。这释放了构造函数引用的真正潜力。
接下来的两个部分相对简单,我们创建了相同的类,一个泛型类和一个非泛型类,以演示它们与在公共类中定义的工厂方法的互操作性。注意,这些类的构造函数与 FuncInt.func()
的方法签名是兼容的。
进入公共类的文件。这个方法就是奇迹发生的地方。
//Here is where the magic happens static <Ob, X, Y, Z> Ob factory(FuncInt<Ob, X, Y, Z> obj, X p1, Y p2, Z p3) { return obj.func(p1, p2, p3); }
我们将该方法标记为静态的,所以我们可以不使用 ConstRefGen 实例,毕竟它是一个工厂方法。注意,factory 方法具有与函数式接口相同的泛型类型参数。注意,方法的返回类型是 Ob,它可以是由我们决定的任何类。当然,X、Y、Z是 Ob 中方法的方法参数。请注意,该函数以 FuncInt 的一个实例作为参数(类类型和方法参数作为类型参数),同时也接受 Ob 类型的类作为方法的参数。
另请参阅: Reactor.js:用于响应式编程的轻量级库
在方法体中,它调用方法引用并将在
factory()
中传递的参数提供给它。
我们的第一个任务是创建一个符合 FuncInt<>
的方法引用。
这里我们分别引用 Automobile 类和 Plane 类的构造函数。
为此,我们调用
factory()
并将它需要的构造函数引用以及
factory()
定义的有关构造函数的参数提供给它。
factory()
可以灵活地创建对各种方法的构造函数引用,因为它是通用的。因为 Plane 类和 Automobile 类的构造函数匹配
FuncInt.func()
的方法签名,所以它们可作为
FuncInt.func()
的方法引用使用。
factory()
通过调用
obj.func(x,y,z)
返回类的一个实例,这是一个构造函数方法引用,当求值时,它将为你提供指定为其参数的类的一个实例。
斟酌这个问题一段时间,会发现它是Java的一个非常有用的补充 ;)
原文链接: jaxenter 翻译:ImportNew.com -Mr.Dcheng
译文链接:[]