【问题标题】:Runnable as method reference可作为方法参考运行
【发布时间】:2020-12-01 10:24:20
【问题描述】:

为什么这段代码不能编译?无法完全掌握细微差别的 java 方法参考:(

public class TestClass {

    static void println() {}
    
   public static void main(String[] args) {

        Runnable r1 = () -> System.out::println; // compilation error
        Runnable r2 = () -> TestClass::println;  // compilation error
        Runnable r2 = () -> System.out.println("Hello World");  // This is fine !!

    }
}

【问题讨论】:

  • 错误信息告诉你什么?你说“打印”,但你没有说打印什么或如何打印
  • 想象一下,“X.y”将访问(执行)X 的方法y,而X::y 引用(复制)X 的方法y 的执行。跨度>

标签: java lambda java-8 method-reference


【解决方案1】:

这里有一点误解,其他答案只提供最终结果。所以这里有一个真实的解释。

在 java 中,有 lambdas (() -> something) 和方法引用 (Class::method)。它们基本上是一样的,只是语法不同(更短)。如果您愿意,您可以混合使用 lambda 和方法引用(lambda 中的 lambda,lambda 中的方法引用)。只要一切都是正确的类型,就可以了。

所以System.out::printlnConsumer<String> 类型的方法引用,因为System.out.println()String 作为参数,并返回void - 那是Consumer<String>。 (还有 System.out.println() 不带参数,在这种情况下,它会是 Runnable

Runnable 有点不同,因为它不接收任何参数或返回值。例如List::clear

至于为什么你的代码是编译错误:

当将 Runnable 声明为 lambda 时,您必须不接收任何参数并返回 void。这个 lambda:Runnable r1 = () -> System.out::println; 不符合条件,因为它不接收任何参数 (() ->),但它的表达式确实返回一个类型 - Consumer<String>(或再次Runnable),而不是void。如果您设法不返回任何内容,则它可能是有效的Runnable,例如

Runnable r1 = () ->  {
  Consumer<String> str1 = System.out::println; // either this
  Runnable str2 = System.out::println; // or this
  return; // return type - void
}

但这有点没有意义。

所以你可以清楚地看到,() -&gt; System.out::println() 实际上是一个提供 RunnableConsumer&lt;String&gt; 的 lambda,所以它的类型应该是

Supplier<Runnable> s = () -> System.out::println; // either this
Supplier<Consumer<String>> s = () -> System.out::println; // or this

要直接使用它,你只需要放弃Supplier&lt;&gt;

Runnable s = System.out::println; // either this
Consumer<String> s = System.out::println; // or this

您只需解释一下您要做什么,我们会为您提供帮助。

【讨论】:

  • 感谢您付出这么多细节的努力。它确实为我清除了一切。我犯了将 Lamba 表达式与方法引用混合在一起的错误,而没有理解在那时如何准确地解释方法引用。在我的案例中,方法引用是返回一个供应商,而我的印象是它将执行并返回 void。
【解决方案2】:

它应该是一个“直接”的方法引用,而不是方法引用所代表的东西的提供者。

Runnable r1 = System.out::println;
Runnable r2 = TestClass::println;

比较

Supplier<Runnable> a = () -> System.out::println;

Runnable b = System.out::println;

【讨论】:

  • 谢谢,我明白我的愚蠢
【解决方案3】:

这不是method references 的工作方式。 你可以这样使用它们:

Runnable r1 = System.out::println;

【讨论】:

  • 即使我弄错了或者上面的句子不正确。实际上() -&gt; System.out::println; 返回一个Supplier&lt;Runnable&gt;,它的工作原理与方法引用的工作原理完全相同......
  • 谢谢,我明白我的愚蠢
【解决方案4】:

因为你需要这样写:

Runnable r1 = System.out::println;
Runnable r2 = TestClass::println;

在这里你可以阅读更多关于方法参考https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html

【讨论】:

  • 谢谢,我明白我的愚蠢
【解决方案5】:

在这种情况下,System.out.println 是一个消费者(它接受一个字符串并对其进行处理)

    Consumer<String> c = System.out::println;
    
    List<String> strings = Arrays.asList("Whee", "Boo");
    strings.forEach(c);  <-- We then pass this consumer here.

或没有:

    List<String> strings = Arrays.asList("Whee", "Boo");
   
    strings.forEach(element -> System.out.println(element)); <-- without method reference

    strings.forEach(System.out::println);
    
    
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-13
    • 2012-03-21
    • 1970-01-01
    • 2018-10-16
    • 2012-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多