This article aims to explain in plain English a syntactic sugar introduced in Java8, method reference.
What is a method reference?
A reference to a class method. The form is roughly:
Type :: Method name
(The constructor isType: : new
)Object :: method name
Example:
String
Static method ofvalueOf
The corresponding method is referenced asString::valueOf
Object
The constructor corresponding to the method reference isObject::new
- Call object
o
Instance method ofhashCode
The corresponding method is referenced aso::hashCode
What is the use of method references?
Before we talk about what method references are for, let’s talk about lambda expressions
Lambda expressions
Before Java8, when we needed to create an instance of an interface, the usual practice was:
-
Create an implementation class for the interface, and then use that class to create instances
-
interface A { void say(String s); } class AImpl implemnets A { @Override public void say(String s) { System.out.println(s); } } A a = new AImpl(); Copy the code
-
-
In the form of anonymous inner classes
-
interface A { void say(String s); } A a = new A() { @Override public void say(String s) { System.out.println(s); }}Copy the code
-
If the implementation class will only be used once, it is simpler to use anonymous inner classes.
There are quite a few interfaces that actually have only one abstract method (the default method is not the extraction method), and for such interfaces we call them functional interfaces. Comparator, Runnable, etc.
The @functionalinterface annotation is usually declared in the JDK, and the compiler will raise an error if an interface with this annotation does not meet the FunctionalInterface specification (which has only one abstract method).
For functional interfaces, Java8 introduced lambda expressions to further simplify writing anonymous inner classes, so non-functional interfaces cannot be created as instances of interfaces in the form of lambda expressions.
Lambda expressions are found in many languages, such as JavaScript, where the function is written as =>, and Java, where it is ->.
The form of a Lambda expression:
(Parameter 1, parameter 2...) -> {// Abstract method implementation code block... }Copy the code
- If there is only one argument, you can omit the parentheses
- If there is only one line of code in a block, you can omit the curly braces and the semicolon at the end of the block
- If there is only one statement in the code block and the statement is a RETURN statement, you can omit the return statement
A shorter lambda expression looks like this:
A -> a+1 () -> system.out.println (" Hello world! )Copy the code
Further simplifying lambda expressions
Method references are introduced to simplify code. Simplify what code? The answer is to simplify lambda expressions, and only for one-line lambda expressions. Here are a few examples:
- Converts an integer number to the corresponding string
// interface A {String m(Integer I); } // create an instance of A, lambda expression A A = I -> string.valueof (I); a.m(1); / / output "1"Copy the code
- Converts an integer string to an integer number
// interface A {Integer m(String s); } // create an instance of A, lambda expression A A = s -> integer.valueof (s); a.m("1"); / / output 1Copy the code
For the above two lambda expressions, there are too many cases where lambda parameters are passed as arguments to static methods. Therefore, method references are introduced to simplify the code. The above two lambda expressions are written as method references:
A a = String::valueOf
A a = Integer::valueOf
Copy the code
Several forms of method references
Here are some of the conversion forms I’ve summarized for method references:
- Class name :: Static method name
- Object :: Instance method name
- Class name :: Instance method name
- Type ::new (constructor reference)
Class name :: Static method name
The static method of a class is called in a lambda expression, and the lambda parameter is passed as an argument to the static method. The return type of the lambda method must correspond to the return type of the static method. Such as:
STR -> integer. parseInt(STR) the corresponding method reference: Integer::parseIntCopy the code
Use the method of erasure, remove the left and right sides of the same parameter list
Object :: Instance method name
A lambda expression calls a method of an object with lambda parameters as arguments to the method, and the method return type of the lambda corresponds to the return type of the object’s instance method. Such as:
class A { void a(String s) { System.out.println(s); } } interface B { void b(String s); } A a = new A(); B b = s -> a.a(s); // equivalent to B B = a::a;Copy the code
Also erase memory, remove the left and right sides of the same parameter list
Class name :: Instance method name
A lambda expression calls an instance method of the first argument of the lambda parameter, with n-1 remaining arguments of the lambda parameter as arguments to the instance method, and the return type of the lambda method corresponding to the return type of the object’s instance method.
str -> str.toLowerCase(); // The corresponding method reference is written as String::toLowerCaseCopy the code
Type: : new
Types are divided into basic data types and reference types.
- Basic data types
There is no new operation for ordinary basic data types, but the corresponding array is created using the new keyword. Lambda parameters are passed in as the length of the array, such as:
- Reference types
Lambda parameters are arguments to the constructor of a class, as in:
conclusion
Method references make Java code much shorter, and all method references need to be written in such a way that the return value type of the lambda method is the same as the return value type of the method reference:
-
Lambda methods return values of type void, so the return value of method references can be void or non-void
-
Lambda methods return non-void, then the return type referenced by the method must remain the same or comply with the Richter substitution rule (LSP)