Java 8 brings with it method references; shortcuts that you can use anywhere you would use a lambda. The Oracle docs describe four types of method reference but do such a poor job of describing them that I felt compelled to describe them myself.
Oracle describe the four kinds of method reference as follows.
Kind | Example |
---|---|
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 |
Static and constructor references are straight forward but it’s their description of instance method references that muddies the waters. What on earth is an instance method of an arbitrary object of a particular type? Aren’t all objects of a particular type? Why is it important that the object is arbitrary?
What they should have written
It’s talking about four types of method reference; constructor references, static method references, instance method references and what it calls instance method references of a particular type. The last one is really just another kind of instance method reference.
What they should have written is this.
Kind | Syntax | Example |
---|---|---|
Reference to a static method | Class::staticMethodName |
String::valueOf |
Reference to an instance method of a specific object | object::instanceMethodName |
x::toString |
Reference to an instance method of a arbitrary object supplied later | Class::instanceMethodName |
String::toString |
Reference to a constructor | ClassName::new |
String::new |
or as lambdas
Kind | Syntax | As Lambda |
---|---|---|
Reference to a static method | Class::staticMethodName |
(s) -> String.valueOf(s) |
Reference to an instance method of a specific object | object::instanceMethodName |
() -> "hello".toString() † |
Reference to an instance method of a arbitrary object supplied later | Class::instanceMethodName |
(s) -> s.toString() |
Reference to a constructor | ClassName::new |
() -> new String() |
I found their description of the two confusing. I prefer to think of the first as an instance method of a specific object known ahead of time and the second as an instance method of an arbitrary object that will be supplied later. Interestingly, this means the first is a closure and the second is a lambda. One is bound and the other unbound.
The distinction between a method reference that closes over something (a closure) and one that doesn’t (a lambda) may be a bit academic but at least it’s a more formal definition than Oracle’s unhelpful description. If you’re interested in the difference between a closure and a lambda, check out my previous article.
The “closure” method reference
The example above (x::toString
) is an instance method reference using a closure. It creates a lambda that will call the toString
method on the instance x
.
|
where the signature of function
looks like this
|
The Supplier
interface must provide a string value (the get
call) and the only way it can do that is if it’s been supplied to it on construction. It’s equivalent to
|
Notice here that the lambda has no arguments (it uses the ‘hamburger’ symbol). This shows that the value of x
isn’t available in the lambda’s local scope and so can only be available from outside it’s scope. It’s a closure because must close over x
.
The anonymous class equivalent really makes this obvious, it looks like this.
|
All three of these are equivalent. Compare this to the lambda variation of an instance method reference where it doesn’t have it’s argument explicitly passed in from an outside scope.
The “lambda” method reference
The other example (String::toString
) is similar to the previous one, it calls the toString
method of a string only this time, the string is supplied to the function that’s making use of the lambda and not passed in from an outside scope.
|
The String
part looks like it’s referring to a class but it’s actually referencing an instance. It’s confusing, I know but to see things more clearly, we need to see the function that’s making use of the lambda. It looks like this.
|
So, the string value is passed directly to the function, it would look like this as a fully qualified lambda.
|
If you expand it fully to an anonymous interface, it looks like this. The x
parameter is made available and not closed over. It’s a lambda rather than a closure.
|
Summary
The difference between the two types of instance method reference is interesting but basically academic. Sometimes, you’ll need to pass something in, other times, the usage of the lambda will supply it for you. My gripe is with Oracle’s documentation. They make a big deal out of the distinction but fail to describe it in an easily understandable way. It’s the canonical reference material but it’s just plain confusing. It feels like interns are producing this stuff.
If you liked this post, you might like my course on Udemy. For a limited time only, get 10% off with this coupon!
Caveat
† There’s a caveat here; the example isn’t a closure, so my comment about that being a distinguishing feature isn’t quiet true. If, as in the later examples, it closes over some x
(as is more likely), great. If however, you use a literal value (as in my starred example), it wont close over the term x
so it’s back to being a lambda. So it oesn’t have to be a closure, it’s just more than likely to be one. For example;
|
Recommended Reading
- What’s New in Java 8, Toby Weston
- Learn Scala for Java Developers, Toby Weston