问题
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
?
回答1:
The syntax of method references is defined in JLS #15.13. In particular it can be of the form:
Primary :: [TypeArguments] Identifier
Where Primary can be, among other things, a:
ClassInstanceCreationExpression
so yes, your syntax is correct. A few other interesting examples:
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(...)
By the way, since you mention static methods, it is interesting to note that you can't create a static method reference from an instance:
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
回答2:
From the State of Lambda
Kinds of method references
There are several different kinds of method references, each with slightly different syntax:
- A static method (
ClassName::methName
)- An instance method of a particular object (
instanceRef::methName
)- A super method of a particular object (
super::methName
)- An instance method of an arbitrary object of a particular type (
ClassName::methName
)- A class constructor reference (
ClassName::new
)- An array constructor reference (
TypeName[]::new
)
回答3:
Saying this:
something(new Main()::meh);
Is approximately equivalent to saying this:
Main x = new Main();
something(() -> x.meh());
Or this:
final Main x = new Main();
something(new Whatever() {
public void meh(Integer ignored) {
x.meh();
}
}
The new instance is "captured" and used in the new lambda instance which was implicitly created from the method handle.
来源:https://stackoverflow.com/questions/22663112/java-8-streams-why-does-this-compile-part-2-or-what-is-a-method-reference-r