Java 8+ 允许将方法引用分配给函数式接口。
那么下面的代码有什么问题(jdoodle 链接)-
public void newMethod(){
Predicate p = String::isBlank;
}
不同于 jdoodle 编译中的错误,在我的本地(gist 链接)我得到错误:
不能从静态上下文中引用非静态方法
但是-下面的东西起作用了
Predicate<String> pp = String::isBlank; //this thing works
这是因为您使用的是原始类型 -
Predicate
。原始功能接口的功能类型是:
泛型函数接口原始类型的函数类型
是泛型函数接口函数类型的擦除I<...>
.I<...>
泛型
Predicate<T>
的函数类型是 (T) -> boolean
(请原谅我自己的原始语法),一个接受 T
并返回 boolean
的函数。因此,原始Predicate
的函数类型是(Object) -> boolean
,(T) -> boolean
的擦除。
这意味着可以将
Objects::isNull
分配给这样一个原始功能接口(但你不应该首先使用原始类型):
// Objects::isNull takes an Object and returns a boolean, so this compiles
Predicate x = Objects::isNull;
方法参考
String::blank
只需要一个String
,而不是任何一种Object
。因此它与函数类型(Object) -> boolean
不一致因此不能分配给
Predicate
类型的变量。
如果
Predicate p = String::isBlank;
有效,那么你就可以做像p.test(1)
这样的事情。并且String::isBlank
必须神奇地确定1
是否“是空白”。
这里的错误信息确实有点令人困惑。
对于
Predicate<String>
,其函数类型的定义不同,它具有函数类型(String) -> boolean
,方法引用String::isBlank
是全等的。
参数化函数接口类型
的函数类型,其中A1...An是类型,I的相应类型参数是P1...Pn,通过应用替换[P1:=A1, .. ., Pn:=An]到泛型函数式接口的函数类型I<A1...An>
.I<P1...Pn>
Predicate p
并不意味着“推断类型参数”。这意味着您已经声明了一个原始的Predicate
,它在Object
上运行。
String::isBlank
在 String
上运行。它可以用于Predicate<String>
,但不能用于原始的Predicate
。