9

OK, the first question in this "series" was this one.

Now, here is another case:

Arrays.asList("hello", "world").stream().forEach(System.out::println);

This compiles, and works...

OK, in the last question, static methods from a class were used.

But now this is different: System.out is a static field of System, yes; it is also a PrintStream, and a PrintStream has a println() method which happens to match the signature of a Consumer in this case, and a Consumer is what forEach() expects.

So I tried this...

public final class Main
{
    public static void main(final String... args)
    {
        Arrays.asList(23, 2389, 19).stream().forEach(new Main()::meh);
    }

    // Matches the signature of a Consumer<? super Integer>...
    public void meh(final Integer ignored)
    {
        System.out.println("meh");
    }
}

And it works!

This is quite a different scope here, since I initiate a new instance and can use a method reference right after this instance is constructed!

So, is a method reference really any method which obeys the signature? What are the limits? Are there any cases where one can build a "@FunctionalInterface compatible" method which cannot be used in a @FunctionalInterface?

4

3 回答 3

20

方法引用的语法在JLS #15.13中定义。特别是它可以是以下形式:

Primary :: [TypeArguments] Identifier

Primary除其他外,可以在哪里:

ClassInstanceCreationExpression

所以是的,你的语法是正确的。其他一些有趣的例子:

this::someInstanceMethod    // (...) -> this.someInstanceMethod(...)
"123"::equals               // (s) -> "123".equals(s)
(b ? "123" : "456")::equals // where b is a boolean
array[1]::length            // (String[] array) -> array[1].length()
String[]::new               // i -> new String[i]
a.b()::c                    // (...) -> a.b().c(...)

顺便说一句,既然你提到了静态方法,有趣的是你不能从实例创建静态方法引用:

class Static { static void m() {} }
Static s = new Static();

s.m(); //compiles
someStream.forEach(s::m); //does not compile
someStream.forEach(Static::m); //that's ok
于 2014-03-26T14:02:57.320 回答
4

来自Lambda 州

方法参考的种类

有几种不同类型的方法引用,每一种的语法略有不同:

  • 静态方法 ( ClassName::methName)
  • 特定对象的实例方法 ( instanceRef::methName)
  • 特定对象的超级方法 ( super::methName)
  • 特定类型的任意对象的实例方法 ( ClassName::methName)
  • 类构造函数引用 ( ClassName::new)
  • 数组构造函数引用 ( TypeName[]::new)
于 2014-03-26T14:02:05.807 回答
3

这么说:

something(new Main()::meh);

大约相当于这样说:

Main x = new Main();
something(() -> x.meh());

或这个:

final Main x = new Main();
something(new Whatever() {
    public void meh(Integer ignored) {
        x.meh();
    }
}

新实例被“捕获”并在从方法句柄隐式创建的新 lambda 实例中使用。

于 2014-03-26T13:57:25.677 回答