问题
I have encountered a short time ago with a competitive answer better than mine that uses a quite new method reference to me as replacement of lambda.
Stream.generate(new AtomicInteger(1)::getAndIncrement)...
I looked the Oracle specifications about the Method references and there are defined 4 types:
- Reference to a static method
ContainingClass::staticMethodName
- Reference to an instance method of a particular object
containingObject::instanceMethodName
- Reference to an instance method of an arbitrary object of a particular type
ContainingType::methodName
- Reference to a constructor
ClassName::new
I struggle with categorizing this one. I haven't found any question on SO or anything relevant explained in the docs. How would be this translated to an anonymous class?
My suspicion is:
IntStream.generate(new IntSupplier() {
AtomicInteger atom = new AtomicInteger(1);
@Override
public int getAsInt() {
return atom.getAndIncrement();
}
})....
... I don't understand how is this possible. At first sight, I would guess the expression is:
IntStream.generate(new IntSupplier() {
@Override
public int getAsInt() {
return new AtomicInteger(1).getAndIncrement();
}
})....
... yet this is nothing else than () -> new AtomicInteger(1).getAndIncrement()
.
Where is this kind of expression defined and how it exactly would be rewritten in the lambda/anonymous class?
回答1:
Well new AtomicInteger(1)
returns an instance, so it's the second one. The exact details of how this is translated are implementation specific, but it's a single instance created and this is back-ed up by the JLS 15.13.3
First, if the method reference expression begins with an ExpressionName or a Primary, this subexpression is evaluated
In plain english, the part before ::
is evaluated when it's declaration is first encountered.
Your assumption how this is translated is almost correct, it's like generating an instance outside of the function itself and using that - since it is effectively final, this is permitted.
回答2:
It's simply the second type: a reference to a method of a specific object, there's no additional logic behind the curtain.
回答3:
You can replace
Stream.generate(new AtomicInteger(1)::getAndIncrement)...
with
AtomicInteger containingObject = new AtomicInteger(1);
Stream.generate(containingObject::getAndIncrement)...
i.e. this method reference falls into the second category of method references - Reference to an instance method of a particular object
.
You should note that the AtomicInteger
instance creation is not part of the implementation of the IntSupplier
. The Java 7 equivalent would be:
AtomicInteger aint = new AtomicInteger(1);
IntStream.generate(new IntSupplier() {
@Override
public int getAsInt() {
return aint.getAndIncrement();
}
})...
.
来源:https://stackoverflow.com/questions/53591305/method-reference-with-a-full-constructor-call-as-a-lambda-expression-in-java