Java 8流,为什么要编译第2部分......或者什么是方法参考,真的吗?

时间:2014-03-26 13:52:56

标签: java java-8 functional-interface

好的,这个“系列”中的第一个问题是this one

现在,这是另一种情况:

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

这编译,并且有效...

好的,在上一个问题中,使用了来自的静态方法。

但现在情况有所不同:System.outstatic的{​​{1}}字段,是的;它也是SystemPrintStream的{​​{1}}方法恰好与PrintStream的签名相匹配,a Consumer is what forEach() expects。< / p>

所以我试过了......

println()

它有效!

这是一个非常不同的范围,因为我启动了一个新实例,并且可以在构造此实例后立即使用方法引用!

那么,是一个方法参考真的任何方法服从签名吗?有什么限制?是否有人可以构建“@FunctionalInterface兼容”方法,无法在Consumer 中使用?

3 个答案:

答案 0 :(得分:20)

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

  

Primary :: [TypeArguments] Identifier

Primary can be, among other things, a:

  

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

答案 1 :(得分:4)

来自State of Lambda

  

各种方法参考

     

有几种不同的方法引用,每种都有   略有不同的语法:

     
      
  • 静态方法(ClassName::methName
  •   
  • 特定对象(instanceRef::methName
  • 的实例方法   
  • 特定对象的超级方法(super::methName
  •   
  • 特定类型(ClassName::methName
  • 的任意对象的实例方法   
  • 类构造函数引用(ClassName::new
  •   
  • 数组构造函数引用(TypeName[]::new
  •   

答案 2 :(得分: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实例中使用,该实例是从方法句柄隐式创建的。