开门见山:
Function 这一函数接口,本身就表达了对传入函数的需求说明。
一个最常见的用途,就是我们已经“准备”好了传入的参数,需要一个函数来处理。建议以下例子中,可以代入 Stream.map 方法来理解,这个方法的入参就是一个函数接口 Function。
对于这个函数,最需要表达的要求(之一),就是这个函数必须能够处理我准备好的参数类型,我们假设这个类型为 Bird 。那么,这个函数实际声明的参数类型,一定必须是 Bird 的父(超)类:否则,我这个 Bird 就传不进去了!
我们来极端理解一下:如果传入的函数的入参,其类型为 Object,那显然可以处理 Bird,符合要求;反之,如果这个类型是 BirdWithManyFeature,那显然就没办法处理我的需求,不符合要求。
返回值的类型也可以这么理解。对于函数接口 Function,我需要对其返回对象进行的操作是明确的,这个对象必须具备 类型 V 的某些特质,但具体是哪个子类就无所谓了。
简而言之:
- 声明一个函数(方法),就像是,我声明了以下这类代码可以处理某一类 (例如 InputClass)的对象,具体地,你给我 AnyClass extends InputClass 都是满足 InputClass 的要求;
- 声明一个函数接口,就像是,我要处理某个对象 T,你给我的函数必须要能处理这个 T,因此你这个函数的入参比如是 T 的父(超)类,具体是 Object 还是别的什么,只要能处理 T 的都行,所以是 ? super T。
后记:
写此文的目的,是因为函数接口这一特性,看似与一些面向过程语言中的“函数引用”类似,但其实又根本不同。对于已经理解或熟练使用的人,恐怕不屑于多费唇舌,因此经常使用一些“严格”、“宽松”这样略显抽象的字眼,让像我这样的门外小白摸不着头脑。但如果将“接口”与“需求说明”这样的概念对比起来,再结合例如 Stream.map 这样常见的典型案例来理解,就很容易消化了。