Exploring Java Method References - [OOP & Java #13]
Tags: computerscience, java
Published: 2021-03-14 08:31:34

# Motivation
According to Oracle's the Java tutorials:
>You use [lambda expressions](https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html) to create anonymous methods. Sometimes, however, a lambda expression does nothing but call an existing method. In those cases, it's often clearer to refer to the existing method by name. Method references enable you to do this; they are compact, easy-to-read lambda expressions for methods that already have a name.

I am aware of method references and thought that they are what they are: a more succinct way of referring to methods without providing explicit information that the compiler already know. What I did not realize was that method references can be categorized into four different types (summary below). Among the four types, 3 of them are fairly easy to understand:
- Call to a constructor by doing `ClassName::new` instead of `() -> new ClassName()`
- Call to a static method by doing `ClassName::methodName` instead of `() -> ClassName.methodName()`
- Call to an instance method of a particular object by doing `ObjectName::methodName` instead of `() -> obj.methodName()`

What intrigued me was the four conditions: **call to an instance method of a particular class**. In that case, will JVM be creating an instance of that class and then invoking the instance method via the newly created instance?

### Summary table

| Type (Reference to)                                             | Syntax                               | Example                       | Lambda Equivalent                                  |
|-----------------------------------------------------------------|--------------------------------------|-------------------------------|----------------------------------------------------|
| a static method                                                 | ContainingClass::staticMethodName    | Integer::parseInt             | str -> Integer.parseInt(str)                       |
| an instance method of  a particular object                      | containingObject::instanceMethodName | Instant.now()::isAfter        | Instant then = Instant.now(); t -> then.isAfter(t) |
| an instance method of an  arbitrary object of a particular type | ContainingType::methodName           | String::toLowerCase           | str -> str.toLowerCase()                           |
| a constructor                                                   | ClassName::new                       | int[]::new HashMap<K, V>::new | len -> new int[len]; () -> new HashMap<K, V>()     |

Note: based on summaries from Oracle's the Java tutorials and Effective Java
Image:
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a0ieniee2n13oz69zmu7.png)

# The hunt
After some Googling, I found a few articles about method references. So there are in fact a few ways we can do a method reference to an instance method without specifying the instance in the method reference.
Examples:
```java
// Method references and their equivalent lambda expressions
String::toLowerCase // (a) -> a.toLowerCase()
String::compareToIgnoreCase // (a, b) -> a.compareToIgnoreCase(b)
Integer::compareTo // (a, b) -> a.compareTo(b)

```
In the above cases, it can be seen that the instance method is going to be invoked on the instance that is passed in as the first parameter. So JVM did not magically create an instance just to invoke an instance method on the specified class.

So in fact, this is a case of **bound vs unbound**.
> In bounded reference, the receiving object is specified in the method reference. Bound references are similar in nature to static references: the function object takes the same arguments as the referenced method.
> 
> In unbound references, the receiving object is specified when the function object is applied, via an additional parameter before the method’s declared parameters. Unbound references are often used as mapping and filter functions in stream pipelines

In my own words:
- Bounded means we specify the object that we are going to call the instance method on.
- Unbounded means we specify that the instance method is going to be called from the first parameter that is passed in, so the first parameter is the object.

# Thoughts
The concept of method references is not difficult. I thought it is interesting to write about it because of the process of how I came to learn more about them.

After some initial research, I came across [this article](https://www.infoworld.com/article/3453296/get-started-with-method-references-in-java.html) which says the following:
>`String::toLowerCase` is an unbound non-static method reference that identifies the non-static `String toLowerCase()` method of the `String` class. However, because a non-static method still requires a receiver object (in this example a `String` object, which is used to invoke `toLowerCase()` via the method reference), the receiver object is created by the virtual machine. `toLowerCase()` will be invoked on this object.

**The receiver object is created by the virtual machine?** I thought to myself: if JVM is going to create an object of the class specified in the method reference in order to call the instance method, how does it know which constructor to invoke? If it simply calls the default constructor, i.e. new ClassName(), what about classes that do not have such a parameterless constructor?

So I opened up jshell and typed in a bunch of classes to verify it:
```java
// driver
class Test { 
	static void print(Function<String, String> fn, String s) {
		System.out.println(fn.apply(s));
	}
}

// test 1
class MyString {
	String toLowerCase(String s) {
		return s.toLowerCase();
	}
}

// test 2
class MyOtherString {
	int one;
	MyOtherString(int one) {
		this.one = one;
	}
	String toLowerCase(String s) {
		return s.toLowerCase();
	}
}

// test
Test.print(String::toLowerCase, "HELLO WORLD");
Test.print(MyString::toLowerCase, "HELLO WORLD");
Test.print(MyOtherString::toLowerCase, "HELLO WORLD");

```

The error messages for my last two test cases are as follows:
>|  Error:
|  incompatible types: invalid method reference
|      unexpected instance method toLowerCase(java.lang.String) found in unbound lookup

Whether my custom classes have a parameterless constructor or not, both calls did not succeed. So it was not a case whereby a magical object of `MyString` or `MyOtherString` will be created and does something like `magicInstance.toLowerCase("HELLO WORLD)"`. 

To end this little piece of article off, I thought of the quote by Albert Einstein:
> “Anyone who has never made a mistake has never tried anything new.”

The process of experimenting with something new or unfamiliar is indeed a great way to learn. At least now I know more about method references and have one article written about it:)

# References
- https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html
- https://www.baeldung.com/java-method-references
- https://www.infoworld.com/article/3453296/get-started-with-method-references-in-java.html
- https://stackoverflow.com/questions/56453749/unexpected-instance-method-function-found-in-unbound-lookup
- https://stackoverflow.com/questions/35914775/java-8-difference-between-method-reference-bound-receiver-and-unbound-receiver/35915104
- https://www.youtube.com/watch?v=hSfylUXhpkA&t=833s