好的,这个“系列”中的第一个问题是this one。
现在,这是另一种情况:
Arrays.asList("hello", "world").stream().forEach(System.out::println);
这编译,并且有效...
好的,在上一个问题中,使用了来自类的静态方法。
但现在情况有所不同:System.out
是static
的{{1}}字段,是的;它也是System
,PrintStream
的{{1}}方法恰好与PrintStream
的签名相匹配,a Consumer
is what forEach()
expects。< / p>
所以我试过了......
println()
它有效!
这是一个非常不同的范围,因为我启动了一个新实例,并且可以在构造此实例后立即使用方法引用!
那么,是一个方法参考真的任何方法服从签名吗?有什么限制?是否有人可以构建“@FunctionalInterface兼容”方法,无法在Consumer
中使用?
答案 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)
各种方法参考
有几种不同的方法引用,每种都有 略有不同的语法:
- 静态方法(
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实例中使用,该实例是从方法句柄隐式创建的。