Java 8 方法引用-使用使用者参数将函数传递给方法

Java 8 方法引用-使用使用者参数将函数传递给方法,java-8,method-reference,functional-interface,Java 8,Method Reference,Functional Interface,我正在学习Java8中的方法引用,我很难理解为什么会这样做 class Holder { private String holded; public Holder(String holded) { this.holded = holded; } public String getHolded() { return holded; } } private void run() { Function<Hold

我正在学习Java8中的方法引用,我很难理解为什么会这样做

class Holder {
    private String holded;

    public Holder(String holded) {
        this.holded = holded;
    }

    public String getHolded() {
        return holded;
    }
}

private void run() {
    Function<Holder, String> getHolded = Holder::getHolded;

    consume(Holder::getHolded); //This is correct...
    consume(getHolded);         //...but this is not
}

private void consume(Consumer<Holder> consumer) {
    consumer.accept(null);
}
类持有者{
私有字符串保持不变;
公共持有人(字符串持有){
this.holded=holded;
}
公共字符串getHolded(){
持有回执;
}
}
私家车{
函数getHolded=Holder::getHolded;
消费(Holder::getHolded);//这是正确的。。。
消费(被抓住);/…但这不是
}
私有无效消费(消费者){
consumer.accept(null);
}
正如您在
run
method-
Holder::getHolded
中看到的,返回未绑定的方法引用,您可以通过将类型为
Holder
的对象作为参数传递来调用该方法引用。像这样:
getHolded.apply(holder)


但是,当它作为方法参数直接调用时,为什么它将这个未绑定的方法引用强制转换为
使用者
,而当我显式地传递
函数
时它却不这样做呢?

这里有两件事,lambda表达式是多表达式——它们是由编译器使用上下文(例如泛型)推断出来的

当您声明
消费时(Holder::getHolded),编译器(根据所谓的特殊无效兼容性规则)将其推断为
消费者

这看起来可能不明显,但想想一个简化的例子。一般来说,调用一个方法并放弃它的返回类型是很正常的,对吗?例如:

List<Integer> list = new ArrayList<>();
list.add(1);
因此,这些都是可能的和有效的声明:

Consumer<Holder> consumer = Holder::getHolded;
Function<Holder, String> function = Holder::getHolded;
Consumer=Holder::getHolded;
Function=Holder::getHolded;

但是在本例中,我们明确地告诉您什么类型是
Holder::getHolded
,这不是编译器的推断,因此
consume(getHolded)失败,
消费者
!=<代码>功能
毕竟

Java8在包
Java.util.function
中引入了4个重要的“函数形状”

  • 使用者->接受接受接受一个参数但不返回任何内容的方法引用(或lambda表达式)
  • 供应商->接受不带参数并返回对象的方法引用(或lambda表达式)
  • 函数->接受方法引用(或lambda表达式),该引用接受一个参数并返回一个对象
  • 谓词->接受方法引用(或lambda表达式),该引用接受一个参数并返回布尔值
有关更多详细信息,请阅读

要回答为什么第一个有效,但第二个错误,请阅读以下内容:

第二句话

消费(getHolded)

不起作用,因为参数
getHolded
的类型是
函数
,而
consume
方法需要类型为
Consumer
的参数。由于
函数
使用者
之间没有父子关系,因此需要显式强制转换,否则编译器将正确地出错

第一句话

消费(Holder::getHolded)

之所以有效,是因为方法
getHolded
被声明为
公共字符串getHolded()
,这意味着它不接受任何参数并返回
字符串。根据新规则,void类型被推断为包含引用方法的类。考虑下面的陈述:

Consumer=Holder::getHolded

即使方法
getHolded
不接受任何参数,这也是一条有效的语句。这有助于推断空洞类型。还有一个例子是你提到的:

函数getHolded=Holder::getHolded


这也是一个有效的语句,您已经说过,函数对象
getholder
是一个
函数
,它返回
String
,并接受类型
Holder
,即使指定的方法引用不带任何参数

请注意,您还应该能够
消费者(getHolded::apply)
。顺便说一下,“holded”应该是“hold”。@Holger:)您无处不在!我甚至没有注意到,很好
consumer(getholder::apply)
将完全符合所提供的相同的无效兼容性规则
consumer(Holder::getholder)
;)规则是由@Eugene belowThanks提到的!这真的帮助我理解了这里正在发生的一切。特别是特殊的空隙相容性rule@TomaszBielaszewski请注意,并非所有内容都符合该规则,如果我没有记错的话,只有4种类型,方法调用、构造函数调用、递增/递减,我忘记了最后一种:)如果需要,搜索JLS。。。
Consumer<Holder> consumer = Holder::getHolded;
Function<Holder, String> function = Holder::getHolded;