6

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?

Nikolas Charalambidis
  • 40,893
  • 16
  • 117
  • 183
  • for better references you can look into the language specs https://docs.oracle.com/javase/specs/jls/se11/html/jls-15.html#jls-15.13 – Naman Dec 03 '18 at 10:15

3 Answers3

5

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.

Eugene
  • 117,005
  • 15
  • 201
  • 306
  • Yup, that's where I would lookup always as a source of truth. :) Would be good to include *At run time, evaluation of a method reference expression is similar to evaluation of a class instance creation expression, insofar as normal completion produces a reference to an object. Evaluation of a method reference expression is distinct from invocation of the method itself.* to help to understand the above quote. – Naman Dec 03 '18 at 10:22
  • *when it's declaration is first encountered* - that's it, now I got it. Thanks :) – Nikolas Charalambidis Dec 03 '18 at 10:52
  • 3
    “when it's declaration is first encountered” is misleading, as it will be evaluated *every time*, the expression `expression::name` is encountered. But it must be emphasized that the evaluation of the generated function instance will not encounter it. Which is different to a lambda expression, which will evaluate the expression to the right of the `->` each time the function is evaluated. – Holger Dec 03 '18 at 11:02
  • @Holger makes sense, the verbiage is awful indeed, thank you for the comment – Eugene Dec 03 '18 at 19:53
2

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();
    }
})...

.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • 1
    I am aware of that and this was my [answer](https://stackoverflow.com/a/53572160/3764965) :) I just don't understand how is this possible. The 2nd category according to your explanation sounds reasonable. Have my +1, yet I wait for a bit more details. – Nikolas Charalambidis Dec 03 '18 at 10:03
2

It's simply the second type: a reference to a method of a specific object, there's no additional logic behind the curtain.

fdreger
  • 12,264
  • 1
  • 36
  • 42