Prerequisites: Functional Interfaces in Java, Lambda Functions
A method is a collection of statements that perform some specific task and return the result to the caller. A method can perform some specific task without returning anything. Methods allow us to reuse the code without retyping the code. In this article, we will see how to use methods as value.
Introduction:
In Java8 we can use method as if they were objects or primitive values and we can treat them as a variable. The example shows the function as a variable in java:
// This square function is a variable getSquare.
Function<Integer, Integer> getSquare = i -> i * i;
// Pass function as a argument to other function easily
SomeFunction(a, b, getSquare);
Sometimes, a lambda expression only calls an existing method. In those cases, it looks clear to refer to the existing method by name. The method references can do this, they are compact, easy-to-read as compared to lambda expression . A method reference is the shorthand syntax for a lambda expression that contains just one method call. Here’s the general syntax of a method reference:
// To refer a method in a object
Object :: methodName
Following is the example of a lambda expression which just call a single method in its entire execution:
// To print all element in a list
list.forEach(s -> System.out.println(s));
To make the code clear and compact, In above example one can turn lambda expression into a method reference:
// Shorthand to print all element in a list
list.forEach(System.out::println);
The method references can only be used to replace a single method lambda expression . A code is more clear and short if one use lambda expression rather than using an anonymous class and one can use method reference rather than using a single function lambda expression to achieve same. In general, one don’t have to pass arguments to method references.
The following example is about performing some operation on elements in the list and add them. The operation to be performed on elements is a function argument and caller can pass accordingly :
public int tranformAndAdd( List<Integer> l, Function<Integer, Integer> ops) { int result = 0 ; for (Integer s : l) result += f.apply(s); return results; } // Operations utility class class OpsUtil { // Function for half the variable public static Integer doHalf(Integer x) { return x / 2 ; } // Square public static Integer doSquare(Integer x) { return x * x; } ... many more operations... } |
Following are the ways to call above method
List<Integer> list = new ArrayLis<>(); // Add some element to list . . . // Using an anonymous class tranformAndAdd( list, new Function<Integer, Integer>() { public Integer apply(Integer i) { // The method return OpsUtil.doHalf(i); } }); // Using a lambda expression tranformAndAdd(list, i -> OpsUtil.doHalf(i)); // Using a method reference tranformAndAdd(list, OpsUtil::doHalf); |
There are Four type method reference:
- Static Method Reference.
- Instance Method Reference of a particular object.
- Instance Method Reference of an arbitrary object of a particular type.
- Constructor Reference.
To look into all this type we will consider a sorting with comparator example.
-
Reference to a static method:
If a Lambda expression is like:
// If a lambda expression just call a static method of a class
(args) -> Class.staticMethod(args)then method reference is like:
// Shorthand if a lambda expression just call a static method of a class
Class::staticMethodExample:
Java
// This Example shows how one can use
// Static method reference to sort
// with custom comparator
import
java.io.*;
import
java.util.*;
// Object need to be sorted.
class
Person {
private
String name;
private
Integer age;
// Constructor
public
Person(String name,
int
age)
{
this
.name = name;
this
.age = age;
}
public
Integer getAge()
{
return
age;
}
public
String getName()
{
return
name;
}
}
public
class
GFG {
// A static method to
// compare with name
public
static
int
compareByName(Person a,
Person b)
{
return
a.getName()
.compareTo(b.getName());
}
// A static method to
// compare with age
public
static
int
compareByAge(Person a,
Person b)
{
return
a.getAge()
.compareTo(b.getAge());
}
// Main
public
static
void
main(String[] args)
{
// List of person
List<Person> personList
=
new
ArrayList<>();
// Add Elements
personList
.add(
new
Person(
"vicky"
,
24
));
personList
.add(
new
Person(
"poonam"
,
25
));
personList
.add(
new
Person(
"sachin"
,
19
));
// Use static method reference to
// sort array by name
Collections.sort(personList,
GFG::compareByName);
System.out.println(
"Sort by name :"
);
personList.stream()
.map(x -> x.getName())
.forEach(System.out::println);
// Use static method reference
// to sort array by age
Collections.sort(personList,
GFG::compareByAge);
System.out.println(
"Sort by age :"
);
personList.stream()
.map(x -> x.getName())
.forEach(System.out::println);
}
}
chevron_rightfilter_noneOutput:Sort by name : poonam sachin vicky Sort by age : sachin vicky poonam
-
Reference to an instance method of a particular object:
If a Lambda expression is like:
// If a lambda expression just call a default method of a ObjectType
(obj, args) -> obj.instanceMethod(args)then method reference is like:
// Shorthand if a lambda expression just call a default method of a ObjectType
ObjectType::instanceMethodExample:
Java
// This Example is same as above but
// using object method reference to
// sort with custom comparator
import
java.io.*;
import
java.util.*;
// Object need to be sorted.
class
Person {
private
String name;
private
Integer age;
// Constructor
public
Person(String name,
int
age)
{
this
.name = name;
this
.age = age;
}
public
Integer getAge()
{
return
age;
}
public
String getName()
{
return
name;
}
}
// Comparator class
class
ComparisonProvider {
// A method to compare with name
public
int
compareByName(Person a,
Person b)
{
return
a.getName()
.compareTo(b.getName());
}
// A method to compare with age
public
int
compareByAge(Person a,
Person b)
{
return
a.getAge()
.compareTo(b.getAge());
}
}
public
class
GFG {
// Main
public
static
void
main(String[] args)
{
// List of person
List<Person> personList =
new
ArrayList<>();
// Add Elements
personList.add(
new
Person(
"vicky"
,
24
));
personList.add(
new
Person(
"poonam"
,
25
));
personList.add(
new
Person(
"sachin"
,
19
));
// A comparator class with multiple
// comaparator methods
ComparisonProvider comparator
=
new
ComparisonProvider();
// Use instance method reference
// to sort array by name
Collections.sort(personList,
comparator::compareByName);
System.out.println(
"Sort by name :"
);
personList.stream()
.map(x -> x.getName())
.forEach(System.out::println);
// Use instance method reference
// to sort array by age
Collections.sort(
personList,
comparator::compareByAge);
System.out.println(
"Sort by age :"
);
personList.stream()
.map(x -> x.getName())
.forEach(System.out::println);
}
}
chevron_rightfilter_noneOutput:Sort by name : poonam sachin vicky Sort by age : sachin vicky poonam
-
Reference to an instance method of an arbitrary object of a particular type:
If a Lambda expression is like:
// If a lambda expression just call a default method of a object
(args) -> obj.instanceMethod(args)then method reference is like:
// Shorthand if a lambda expression just call a default method of a object
obj::instanceMethodExample:
Java
// This Example shows how one can use
// Instance type method reference
// to sort with custom comparator
import
java.io.*;
import
java.util.*;
public
class
GFG {
// Main
public
static
void
main(String[] args)
{
// List of person
List<String> personList
=
new
ArrayList<>();
// Add Elements
personList.add(
"vicky"
);
personList.add(
"poonam"
);
personList.add(
"sachin"
);
// Method reference to String type
Collections.sort(
personList,
String::compareToIgnoreCase);
personList.forEach(
System.out::println);
}
}
chevron_rightfilter_noneOutput:poonam sachin vicky
-
Constructor method reference:
If a Lambda expression is like:
// If a lambda expression just create a object
(args) -> new ClassName(args)then method reference is like:
// Shorthand if a lambda expression just create a object
ClassName::newExample:
Java
// This Example shows how one
// can use constructor method reference
import
java.io.*;
import
java.nio.charset.Charset;
import
java.util.*;
import
java.util.function.*;
// Object need to be sorted.
class
Person {
private
String name;
private
Integer age;
// Constructor
public
Person()
{
Random ran =
new
Random();
// length is bounded by 7
byte
[] array =
new
byte
[
7
];
ran.nextBytes(array);
// Asigning Random values
// to name and age
this
.name
= ran
.ints(
97
,
122
+
1
)
.limit(
7
)
.collect(StringBuilder::
new
,
StringBuilder::appendCodePoint,
StringBuilder::append)
.toString();
this
.age = age;
}
public
Integer getAge()
{
return
age;
}
public
String getName()
{
return
name;
}
}
public
class
GFG {
// Get List of objects of given
// length and Supplier
public
static
<T> List<T>
getObjectList(
int
length,
Supplier<T> objectSupply)
{
List<T> list =
new
ArrayList<>();
for
(
int
i =
0
; i < length; i++)
list.add(objectSupply.get());
return
list;
}
public
static
void
main(String[] args)
{
// Get 10 person by suppliying
// person supplier, Supplier is
// created by person constructor
// reference
List<Person> personList
= getObjectList(
5
, Person::
new
);
// Print names of personList
personList.stream()
.map(x -> x.getName())
.forEach(System.out::println);
}
}
chevron_rightfilter_noneOutput:vzskgmu iupltfx kocsipj lyvhxsp hbdphyv
Conclusion:
As mentioned above, if a lambda expression only calls an existing method then using method reference can make code more readable and clear. There are many more things we can do with Java8 Lambda and Method References while using Java streams.
Attention reader! Don’t stop learning now. Get hold of all the important Java Foundation and Collections concepts with the Fundamentals of Java and Java Collections Course at a student-friendly price and become industry ready.