【问题标题】:Why does functional interface with void return-type method accept any return-type method? [duplicate]为什么具有 void 返回类型方法的功能接口接受任何返回类型方法? [复制]
【发布时间】:2019-09-27 11:09:09
【问题描述】:

我们有这个代码:

public class Test {
    public static Object foo() {
        System.out.println("Foo");
        return new Object();
    }

    public static void main(String[] args) {
        J j = Test::foo;
        j.m();
    }

}
interface J {
    void m();
}

并且此代码将起作用。关键是

J j = Test::foo;

虽然interface J 声明它有一个void 函数,但Test::foo 返回一个Object

虽然我们不能在实现接口时覆盖方法(这很明显)。 这仅在接口的方法为void 时有效,否则代码不会被编译。有人能说出为什么这会以它的工作方式工作吗? :D

【问题讨论】:

  • lambda 只是一个语法糖,当返回类型不是void 时添加一个return 语句。如果返回不是 void 并且类型不匹配,则编译器会抱怨。
  • 对此可能有很好的技术解释,但基本上它是语法糖。你总是可以忽略一个返回值(来自foo()),但是你不能弥补一个,所以它不能反过来工作(foo()voidm()有一个返回类型) .
  • 我想你已经得到了答案:返回类型不是void时会添加return语句
  • 我认为它记录在JLS 15.13.2. Type of a Method Reference - 相关文本:“......方法引用表达式与函数类型一致,如果......函数类型的结果是无效...... "

标签: java void functional-interface


【解决方案1】:

虽然interface J 声明它有一个void 函数,但Test::foo 返回一个Object

Test::foo 返回一些东西是不准确的。在不同的情况下,它可能意味着不同的东西。

Supplier<Object>  a = Test::foo;
J                 b = Test::foo;
Runnable          c = Test::foo;

更准确的说法是Test::foo 可以表示a target type the functional method 其中返回voidObject

这是expression statement (jls-14.8)的一个例子。

如果目标类型的函数类型有 void 返回,则 lambda 主体是语句表达式 (§14.8) 或 void 兼容块 (§15.27.2)。 ...
表达式语句通过对表达式求值来执行;如果表达式有值,该值被丢弃。

【讨论】:

  • 表达式语句是一个表达式,后面跟一个分号,就像表达式a.foo()可以写成语句a.foo();。所以方法引用表达式Test::foo 不是表达式语句。 (它也不是 lambda。)
【解决方案2】:

我不确定究竟是什么让您感到困惑,所以这里有一些其他方式可以帮助您查看示例。


J j = Test::foo;

可以改写为

J j = () -> Test.foo();

因为它从J 功能接口向m() 方法提供主体,并且该方法不需要任何参数(这就是它以() -&gt; 开头的原因)。

但这可以看作是较短的版本

J j = new J(){
    public void m(){
        Test.foo(); //correct despite `foo` returning value    
    }
};

这是正确的,因为Java允许我们忽略被调用方法的返回值,就像List#add(E element)返回boolean值一样,但是我们仍然可以编写list.add(1)这样的代码而不必处理返回值.

【讨论】:

  • 但是,如果我编辑接口方法并使其返回int,例如,我可以将foo() 转换为int,lambda 也会自动使J j = () -&gt; (int) Test.foo(); 成为某事喜欢J j = () -&gt; return (int) Test.foo();?忽略那个 ClassCastException
  • 如果您需要在标准匿名类中显式转换值,那么您很可能还需要在 lambda 中转换它,这会阻止您将其重写为方法引用。如果您描述了您不能拥有 ()-&gt;Test.foo(); 并且您需要将其转换为 int 就像您显示的 J j = () -&gt; (int) Test.foo(); 一样(不 - 它不会自动完成)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-15
  • 2011-05-16
  • 2017-05-09
相关资源
最近更新 更多