Java8中的方法引用有具体类型吗?如果有,是什么类型?

Java8中的方法引用有具体类型吗?如果有,是什么类型?,java,lambda,functional-programming,java-8,method-reference,Java,Lambda,Functional Programming,Java 8,Method Reference,这个问题与我们的关系非常密切。然而,我觉得这个问题的公认答案并不那么确定 那么,Java8中方法引用的类型是什么?下面是如何将方法引用“转换”(提升?)到java.util.function.function中的一个小演示: package java8.lambda; import java.util.function.Function; public class Question { public static final class Greeter { private fin

这个问题与我们的关系非常密切。然而,我觉得这个问题的公认答案并不那么确定

那么,Java8中方法引用的类型是什么?下面是如何将方法引用“转换”(提升?)到
java.util.function.function
中的一个小演示:

package java8.lambda;

import java.util.function.Function;

public class Question {
  public static final class Greeter {
    private final String salutation;

    public Greeter(final String salutation) {
      this.salutation = salutation;
    }

    public String makeGreetingFor(final String name) {
      return String.format("%s, %s!", salutation, name);
    }
  }

  public static void main(String[] args) {
    final Greeter helloGreeter = new Greeter("Hello");

    identity(helloGreeter::makeGreetingFor)
      .andThen(g -> "<<<" + g + ">>>")
      .apply("Joe");

    //Compilation error: Object is not a function interface
//    Function
//      .identity()
//      .apply(helloGreeter::makeGreetingFor)
//      .andThen(g -> "<<<" + g + ">>>")
//      .apply("Joe");

    Function
      .<Function<String,String>>identity()
      .apply(helloGreeter::makeGreetingFor)
      .andThen(g -> "<<<" + g + ">>>")
      .apply("Joe");

    //Compilation error: Cannot resolve method 'andThen(<lambda expression>)'
//    (helloGreeter::makeGreetingFor)
//      .andThen(g -> "<<<" + g + ">>>")
//      .apply("Joe");

//    java.lang.invoke.LambdaMetafactory ???
  }

  private static <I,O> Function<I,O> identity(final Function<I,O> fun1) {
    return fun1;
  }
}
包java8.lambda;
导入java.util.function.function;
公开课问题{
公共静态末班迎宾员{
私人最后的弦乐敬礼;
公共迎宾员(最后的弦乐敬礼){
这个。敬礼=敬礼;
}
公共字符串makeGreetingFor(最终字符串名){
返回字符串。格式(“%s,%s!”,称呼,名称);
}
}
公共静态void main(字符串[]args){
最终迎宾员helloGreeter=新迎宾员(“你好”);
标识(helloGreeter::makeGreetingFor)
.然后(g->“”)
.申请(下称“乔”);
//编译错误:对象不是函数接口
//作用
//.identity()
//.apply(helloGreeter::makeGreetingFor)
//.然后(g->“”)
//.申请(下称“乔”);
作用
.identity()
.apply(helloGreeter::makeGreetingFor)
.然后(g->“”)
.申请(下称“乔”);
//编译错误:无法解析方法“andThen()”
//(helloGreeter::makeGreetingFor)
//.然后(g->“”)
//.申请(下称“乔”);
//java.lang.invoke.LambdaMetafactory???
}
专用静态函数标识(最终函数fun1){
返回fun1;
}
}

那么,有没有一种不那么痛苦(更直截了当)的方法将方法引用强制转换为可传递的编译/具体类型?

对于使用传递的参数作为输入参数的函数来说,方法引用只是一种语法糖。因此,您可以通过以下方式分配它们:

Runnable runnable = System.out::println;
Consumer consumer = System.out::println;
类型是推断的,并且依赖于上下文

你的情况:

Function<String, String> foo = helloGreeter::makeGreetingFor;
函数foo=helloGreeter::makeGreetingFor; 它等于:

Function<String, String> foo = s -> helloGreeter.makeGreetingFor(s);
函数foo=s->helloGreeter.makeGreetingFor(s);

首先,方法引用“对于已经有名称的方法,是紧凑、易于阅读的lambda表达式”(请参阅)

事实上,您要求的是lambda表达式的类型。这一点在本文中有明确的解释

简而言之,提到了三种兼容性:

  • 作业上下文
  • 调用上下文
  • 铸造上下文
  • lambda表达式或方法引用的类型由编译器推断。由于现在可以(而且必须)考虑到多个上下文,Java8对类型推断有了很大的增强

    lambda表达式的唯一限制是推断类型必须是。事实上,相等的lambda表达式可以有不同的上下文类型。

    来自:

    方法引用表达式在赋值上下文中兼容, 调用上下文,或者如果T是 功能接口类型(§9.8),且表达式与 从T派生的地面目标类型的功能类型

    如果方法引用表达式与目标类型T兼容, 那么表达式的类型U就是派生的地面目标类型 从T


    基本上,方法引用的类型是上下文所期望的类型。独立于上下文,方法引用实际上没有类型。没有办法传递一个“原始”方法引用,然后在以后的某个时候将其转换为函数或使用者或任何东西。

    如果您只有一个方法引用
    helloGreeter::makeGreetingFor
    ,它就没有类型

    如果要为方法引用指定类型而不将其赋值或作为参数传递(将其赋值给参数),可以强制转换它:

    String greeting =
        ((Function<String, String>)helloGreeter::makeGreetingFor)
            .apply("Joe");
    
    字符串问候语=
    ((函数)helloGreeter::makeGreetingFor)
    .申请(下称“乔”);
    
    函数f=helloGreeter::makeGreetingFor?将推断方法引用的类型。相同的方法引用可以用作使用者、函数或其他函数接口,具体取决于上下文。如果您觉得某个问题的回答不够好,您应该对原始问题给予奖励,而不是第二次提问。你的问题与前面的问题有什么不同吗?或者我可以把它作为一个副本来结束吗?我想,本质上,它们是一样的。虽然这里的答案似乎更具体。这个问题掩盖了一个错误的假设:所有表达式都有一个内在的(自下而上的)类型。方法引用和lambda是poly表达式的示例,poly表达式的类型取决于它们的上下文。方法引用或lambda的类型仅仅是它被分配/转换到的类型(前提是该类型与所讨论的lambda/方法引用兼容)。@Andrey您的惊讶是错误的;Java中的每个表达式都有一个具体的编译时类型。这里的新功能是,对于某些表达式,该类型可能受表达式出现的上下文的影响(或需要来自该上下文的类型信息),例如赋值目标类型。lambda和method refs有一个类型,但这不是由表达式本身决定的,而是由外部类型信息决定的(赋值或强制转换目标类型,当然要经过适用性检查)。