First of all the map method does not know itself what to do with method references. That's the compiler's job. In both cases, map expects :
Function<? super PackageName.outer,? extends Integer>
For you particular question both method references according to the docs are a Reference to an instance method of a particular object
Regarding how the compiler deals with lambdas and method references and translates them to bytecode this document is highly recommended reading. The most relevant part to your question (emphasis mine to summarise):
When the compiler encounters a lambda expression, it first lowers
(desugars) the lambda body into a method whose argument list and
return type match that of the lambda expression, possibly with some
additional arguments (for values captured from the lexical scope, if
any.) At the point at which the lambda expression would be captured,
it generates an invokedynamic call site, which, when invoked, returns
an instance of the functional interface to which the lambda is being
converted. This call site is called the lambda factory for a given
lambda. The dynamic arguments to the lambda factory are the values
captured from the lexical scope. The bootstrap method of the lambda
factory is a standardized method in the Java language runtime library,
called the lambda metafactory. The static bootstrap arguments capture
information known about the lambda at compile time (the functional
interface to which it will be converted, a method handle for the
desugared lambda body, information about whether the SAM type is
serializable, etc.)
Method references are treated the same way as lambda expressions,
except that most method references do not need to be desugared into a
new method; we can simply load a constant method handle for the
referenced method and pass that to the metafactory
Instance-capturing method reference forms include bound instance
method references (s::length, captured with reference kind
invokeVirtual)
The bytecode for your 2 cases is :
outer::instanceMethod
// handle kind 0x5 : INVOKEVIRTUAL
PackageName/outer.getVal()I,
(LPackageName/outer;)Ljava/lang/Integer;
MyClass::instanceMethod
// handle kind 0x5 : INVOKEVIRTUAL
PackageName/MyClass.f(LPackageName/outer;)Ljava/lang/Integer;,
(LPackageName/outer;)Ljava/lang/Integer;
Note that, although the second line is more complicated in the second case, the last line is the same. In both cases the compiler just sees a function that takes an outer and returns an Integer. And that matches what map expects.
Method References are described in the language spec 15.13 Method Reference Expressions. The fact that the target reference of a method reference is an implicit first argument of the method is mentioned at 15.13.3 Run-Time Evaluation of Method References.
If the compile-time declaration is an instance method, then the target
reference is the first formal parameter of the invocation method.
Otherwise, there is no target reference
this(i.e. theouterinstance on which the method is called), the output is the value returned by the method.thisas the first argument by default, so no function has 'zero' arguments. But where in the docs is this behavior/convention mentioned?Arrays.asList(new outer(2)).stream()in a very convoluted way of creating a single element stream, wrapping the instance in an array, wrapping the array in a list, to eventually create a Stream from a List. Just useStream.of(new outer(2))instead.