方法引用让你可以重复使用现有的方法定义,并像Lambda一样传递它们。
在一些情况下,比起使用Lambda表达式,它们似乎更易读,感觉也更自然。
下面就是借助更新的Java8 API用方法引用写的一个排序的例子:![6X28A`M~%WN]DI{(Q${F@C7.png](/uploads/projects/u12396954@dy0839/acc3151c1cf2a2fb50e3caf6259195ed.png)
为什么应该关心方法引用?
方法引用可以被看作仅仅调用特定方法的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。
可以这样做:![VX%QH}C)37[)E_X%9`][N7Q.png](https://cdn.nlark.com/yuque/0/2021/png/12773302/1633578536828-b09782e3-0854-447d-95b8-c251eeaf8e77.png#clientId=ua0843ab3-7354-4&from=drop&id=lXqc0&margin=%5Bobject%20Object%5D&name=VX%25QH%7DC%2937%5B%29E_X%259%60%5D%5BN7Q.png&originHeight=148&originWidth=832&originalType=binary&ratio=1&size=30236&status=done&style=none&taskId=uf09ee91b-e8b5-43e1-8091-6b9a0f4f1c9)<br />等价于:<br /><br />如果构造函数的签名是Apple (Integer weight), 那么它就适合Function接口的签名,于是你可以这样写:<br />![X~2YHT23}]$XXYE8F7OUIA7.png](/uploads/projects/u12396954@dy0839/88d0a5421cfdb84ba33b0f1a6d2efe6c.png)
等价于:
在下面的代码中,一个由Integer构成的List中的每个元素都通过我们前面定义的类似的map方法传递给了Apple的构造函数,得到了一个具有不同重量苹果的List:

等价于:
<br />
