方法引用让你可以重复使用现有的方法定义,并像Lambda一样传递它们。
在一些情况下,比起使用Lambda表达式,它们似乎更易读,感觉也更自然。
下面就是借助更新的Java8 API用方法引用写的一个排序的例子:
为什么应该关心方法引用?
方法引用可以被看作仅仅调用特定方法的Lambda的一种快捷写法。
它的基本思想是,如果一个Lambda代表的只是“直接调用这个方法”,那最好还是用名称来调用它,而不是去描述如何调用它。
事实上,方法引用就是让你根据已有的方法实现来创建Lambda表达式。
但是显式地指明方法的名称,你的代码的可读性会更好。
它是如何工作的呢?
当你需要使用方法引用时,目标引用放在分隔符 : : 前,方法的名称放在后面。
例如,Apple: :getWeight就是引用了Apple类中定义的方法getweight。
请记住,不需要括号,因为你没有实际调用这个方法。
方法引用就是Lambda表达式(Apple a) -> a. getweight ()的快捷写法。
你可以把方法引用看作针对仅仅涉及单一方法的Lambda的语法糖,因为你表达同样的事情时要写的代码更少了。
如何构建方法引用
方法引用主要有三类。
1)指向静态方法的方法引用
例如Integer的parseInt方法,写作Integer :: parseInt。
2)指向任意类型实例方法的方法引用
例如string的length方法,写作String :: length。
3)指向现有对象的实例方法的方法引用
假设有一个局部变量expensiveTransaction用于存放Transaction类型的对象,它支持实例方法getValue,那么就可以写expensiveTransaction :: getValue )。
第二种和第三种方法引用可能看起来有点儿晕。
类似于String :: length的第二种方法引用的思想就是你在引用一个对象的方法,而这个对象本身是Lambda的一个参数。
例如,Lambda表达式(String s) -> s. toUppeCase()可以写作String :: toUpperCase。
但第三种方法引用指的是,你在Lambda中调用一个已经存在的外部对象中的方法。
例如,Lambda 表达式() ->expensiveTransaction . getValue()可以写作expensiveTransaction :: getValue。
依照一些简单的方子,就可以将Lambda表达式重构为等价的方法引用,如图3-5所示。
请注意,还有针对构造函数、数组构造函数和父类调用( super-call)的一些特殊形式的方法引用。
举一个方法引用的具体例子吧。
比方说你想要对一个字符串的List排序,忽略大小写。
List的sort方法需要一个Comparator作为参数,Comparator描述了一个具有(T, T) -> int签名的函数描述符。
你可以利用String类中的compareToIgnoreCase方法来定义一个Lambda表达式(注意compareToIgnoreCase是String类中预先定义的)。
Lambda表达式的签名与Comparator的函数描述符兼容。
利用前面所述的方法,这个例子可以用方法引用改写成下面的样子:
请注意,编译器会进行一种与Lambda表达式类似的类型检查过程,来确定对于给定的函数式接口,这个方法引用是否有效:方法引用的签名必须和上下文类型匹配。
构造函数引用
对于一个现有构造函数,你可以利用它的名称和关键字new来创建它的一个引用:ClassName :: new。
它的功能与指向静态方法的引用类似。
例如,假设有一个构造函数没有参数。
它适合supplier的签名() -> Apple。
可以这样做:
等价于:
在下面的代码中,一个由Integer构成的List中的每个元素都通过我们前面定义的类似的map方法传递给了Apple的构造函数,得到了一个具有不同重量苹果的List:
<br />