In the post Lambda expression in Java we have already seen how Lambda expression provides an instance of functional interface and implements the abstract method of the functional interface. Though sometimes, a lambda expression is used just to call an existing method. In those cases you can refer to the existing method by name using Method references in Java. Method reference is a compact and more readable lambda expressions for methods that already have a name.
For example consider the following lambda expression-
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); list.forEach((Integer a) -> System.out.println(a));
Here lambda expression is just calling an existing method which can be done using method reference making the code more readable and concise.
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5); list.forEach(System.out::println);
Method reference also needs a target type
Java method reference can be termed as a special form of lambda expression as method reference also needs a target type context (a compatible functional interface) and it also creates an instance of functional interface just like lambda expression does. Which also means method reference can only be used for a single method.
Where these two differ is lambda expression can also provide implementation for an abstract method where as method reference refers to an existing method.
Java Method reference syntax
As we have already seen in the example a new double colon operator (::) is added in Java to be used with method reference.
Class or object that contains the method is on the left side of the double colon operator and the name of the method in on the right side of the operator.
Kinds of Method References
There are four kinds of method references in Java
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 method reference
Following example shows how to use static method reference in Java.
public class MethodRef { public static <T> List<T> filter(List<T> myList, Predicate<T> predicate) { List<T> filterdList = new ArrayList<T>(); for(T element: myList) { if(predicate.test(element)) { filterdList.add(element); } } return filterdList; } public static boolean isMoreThanValue(int i) { return i > 10; } public static void main(String[] args) { List<Integer> myList = Arrays.asList(25, 5, 17, 1, 7, 14, 9, 11); System.out.println("Method call as lambda expression"); List<Integer> filterdList = filter(myList, (i) -> MethodRef.isMoreThanValue(i)); System.out.println("Filtered elements- " + filterdList); System.out.println("Method call using method reference"); filterdList = filter(myList, MethodRef::isMoreThanValue); System.out.println("Filtered elements- " + filterdList); } }Output
Method call as lambda expression Filtered elements- [25, 17, 14, 11] Method call using method reference Filtered elements- [25, 17, 14, 11]
In the example static method isMoreThanValue()
is called using method reference MethodRef::isMoreThanValue
.
In the filter method one of the argument is of type Predicate. Predicate is a functional interface which has an abstract method test() which evaluates this predicate on the given argument and return a boolean value (true or false).
Static method isMoreThanValue() is an implementation of the abstract method test() of the Predicate functional interface.
When you make a method call filter(myList, MethodRef::isMoreThanValue)
, Java can infer from the context that isMoreThanValue() is an implementation for Predicate interface.
Method reference to an instance method
In this case you use an object of the class to refer the method rather than using the class name.
public class MethodRef { public <T> List<T> filter(List<T> myList, Predicate<T> predicate) { List<T> filterdList = new ArrayList<T>(); for(T element: myList) { if(predicate.test(element)) { filterdList.add(element); } } return filterdList; } public boolean isMoreThanValue(int i) { return i > 10; } public static void main(String[] args) { List<Integer> myList = Arrays.asList(25, 5, 17, 1, 7, 14, 9, 11); MethodRef obj = new MethodRef(); System.out.println("Method call as lambda expression"); List<Integer> filterdList = obj.filter(myList, (i) -> obj.isMoreThanValue(i)); System.out.println("Filtered elements- " + filterdList); System.out.println("Method call using method reference"); filterdList = obj.filter(myList, obj::isMoreThanValue); System.out.println("Filtered elements- " + filterdList); } }Output
Method call as lambda expression Filtered elements- [25, 17, 14, 11] Method call using method reference Filtered elements- [25, 17, 14, 11]
It is the same example as the static method reference only change is now instance of the class is used for method reference. Methods are also not required to be static now.
Reference to an instance method of an arbitrary object of a particular type
In the previous example specific object of the class is used but you may have a scenario in which you want to specify an instance method that can be used with any object of a given class. In that case method reference will have the following form-
ClassName::instanceMethodName
In this case, the first parameter of the functional interface matches the object that has been used to invoke the method and any other parameters are passed to the method.
In the example there a class Person with fields firstName, lastName, age and you need to get the count of Persons with age greater than 50. In this scenario isAgeGreater() method has to be invoked for all the Person objects.
class Person { private String firstName; private String lastName; private int age; public Person(String firstName, String lastName, int age){ this.firstName = firstName; this.lastName = lastName; this.age = age; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public int getAge() { return age; } // This becomes the abstract method (test) implementation // of the functional interface boolean isAgeGreater(int age) { return this.getAge() > age; } } @FunctionalInterface interface TestInterface { boolean test(Person person, int age); } public class MethodRef { public static void main(String[] args) { List<Person> tempList = createList(); int count = ageCounter(tempList, Person::isAgeGreater, 50); System.out.println("Person count age greater than 50- " + count); } static int ageCounter(List<Person> list, TestInterface ref, int age) { int count = 0; for(Person person : list) { // first param becomes the invoking object // other parameters are passed to method if(ref.test(person, age)) count++; } return count; } private static List<Person> createList(){ List<Person> tempList = new ArrayList<Person>(); tempList.add(new Person("Joe","Root", 28)); tempList.add(new Person("Mathew","Hayden", 42)); tempList.add(new Person("Richard","Hadlee", 55)); tempList.add(new Person("Sunil","Gavaskar", 65)); tempList.add(new Person("Brian","Lara", 45)); return tempList; } }
Constructor reference
You can also reference a constructor which is similar to method reference except that the name of the method is new in this case.
Syntax for the constructor reference is as follows-
classname::new
Constructor reference Java example
In the method copyElements()
one of the parameter is of type Supplier
which is a functional interface defined in
java.util.function
package. The functional interface Supplier contains one method get that takes no arguments and
returns an object. A new ArrayList instance is passed to Supplier as a constructor reference.
public class MethodRef { public static void main(String[] args) { List<Integer> myList = Arrays.asList(25, 5, 17, 1, 7, 14, 9, 11); List<Integer> tempList = copyElements(myList, ArrayList::new); System.out.println("Copied list- " + tempList); } public static List<Integer> copyElements(List<Integer> sourceList, Supplier<List<Integer>> destList) { List<Integer> list = destList.get(); for (Integer i : sourceList) { list.add(i); } return list; } }
That's all for the topic Method Reference in Java. If something is missing or you have something to share about the topic please write a comment.
You may also like
- Exception Handling With Java Lambda Expressions
- Built-in Functional Interfaces in Java
- Java ThreadPoolExecutor - Thread Pool with ExecutorService
- Java Stream – Convert a Stream to Map
- Check if a String is Null or Empty in Java
- Spring XML Configuration Example
- Spring Boot + Data JPA + Oracle One to Many Example
- Spring Boot and Dependency Injection
- First React App – Hello World React Example
No comments:
Post a Comment