Method Reference(::) Java 8

Method ReferenceMethod Reference is a wonderful feature introduced in Java 8. Apart from taking advantage of functional programming, one of the biggest advantage in using a Lambda expression is to minimize the lines of code. Similarly, Method reference also minimizes lines of code even more than Lambda. However, we use both of them in the presence of functional interfaces only. Moreover, It is also a concise and simpler form of lambda expression. In this article, we will also learn how to change a Lambda expression into a method reference. Let’s start discussing about ‘Method Reference(::) Java 8’ and it’s related concepts.​

What is Method Reference(::) ?

As we have seen in Lambda expression’s topic that we use lambda expressions to implement Functional interfaces with minimum lines of code and even to get better code readability. Similarly, we can use Method References(::) Java 8 to implement Functional interfaces with even lesser code again than lambda expressions and this time we get the benefit of code re-usability as well, because we don’t provide implementation for functional interface. Instead, we provide reference to already existing method(with similar argument types) to simplify the implementation of the functional interface using double colon (::) operator. This process of providing reference to pre-existing method is called Method reference.

From the above definition it is clear that while applying Method References our focus is always on the pre-existing methods which are well suited to the implementation of Functional Interface. In fact, pre-existing methods should have same arguments in number & type and there are no restrictions on their return type as such. Of course, here one thing is equally important to keep in mind that Method references & Lambda expressions both can only be used in context of Functional Interfaces.

interface A {
	public void getName(String name);
}

public class Test {

	public static void getInfo(String info) {
		System.out.println(info);
	}

	public static void main(String[] args) {
		A a = (String s) -> System.out.println(s); //providing implementation of getName(String name) using Lambda Expression
		a.getName("SAM is executing");

		A a1 = Test::getInfo; // refering to pre-existing getInfo(String info) of class Test as arguments are same as getName(String name)
		a1.getName("getInfo() of Test class is executing");
	}
}
output :

SAM is executing
getInfo() of Test class is executing

In the above code snippet, Interface A, is a functional interface. The Single abstract method(SAM), getName(String name) of interface A has the same argument in number & type as the pre-existing method getInfo(String info) of class Test. Therefore, we can refer getInfo(String info) as an implementation of Functional interface A without any problem. Hence, the syntax for Method reference will be ClassName::methodName if it is static method.

Syntax to write Method References

First, we will categorize the method references before knowing how to write them. Here, syntax to write Method Reference(::) in Java 8 is different in different cases. In general, we can provide Method references in three ways, sometimes called the types of it.

  1. Static Method References
  2. Instance method/non-static Method References
  3. Constructor References

Now, let’s try to observe them one by one from below table.

                                                                        Types of Method References

Note :  In addition, we have two more besides above three:

  1. Method References of an arbitrary object of a given type
  2. Method References from a super class method.                                                                                                                                                       We will cover them separately in below sections.

Examples of each Type 

Furthermore, in this section we will see the example of each type one by one.

Method reference to a static method of a class :

interface A {
	public boolean checkSingleDigit(int x);
}

class Digit {
	public static boolean isSingleDigit(int x) {
	    return x > -10 && x < 10;
	}
}

public class TestStaticMethodReference {

	public static void main(String[] args) {
		
		//*** Using Lambda Expression ***//
		A a1 = (x) -> { return x > -10 && x < 10;};
		System.out.println(a1.checkSingleDigit(10));
		
		//*** Using Method Reference ***//
		A a2 = Digit::isSingleDigit;
		System.out.println(a2.checkSingleDigit(9));
	}
}

In the above example, we have functional Interface A. We have implemented the single abstract method checkSingleDigit(int x) using Lambda expression in highlighted line. But while using Method reference, we have just referred the similar already existing static method isSingleDigit(int x) of class Digit.

Method reference to an Instance method of a class :

interface B {
    public  void add(int x, int y);
}

class Addition {
	public void sum(int a, int b) {
	    System.out.println("The sum is :"+(a+b));
	}
}

public class TestInstanceMethodReference {

	public static void main(String[] args) {
		
		Addition addition = new Addition();
		//*** Using Lambda Expression ***//
		B b1 = (a,b) -> System.out.println("The sum is :"+(a+b));
		b1.add(10, 14);
		
		//*** Using Method Reference ***//
		B b2 = addition::sum;
		b2.add(100, 140);
	}
}

In the above example, we have functional Interface B. We have implemented the single abstract method add(int x, int y) using Lambda expression in highlighted line. While using Method reference, we have just referred the similar already existing method sum(int a, int b) of class Addition but after creating an object of the class this time.

Constructor Reference 

When single abstract method’s return type is any Object, we will go with the constructor reference.

interface C {
	public Employee getEmployee();
}

interface D {
	public Employee getEmployee(String name, int age);
}

class Employee {
	String eName;
	int eAge;
	
	public Employee(){} 
	
	public Employee(String eName, int eAge) {
		this.eName = eName;
		this.eAge = eAge;
	}
	
	public void getInfo() {
		System.out.println("I am a method of class Employee");
	}
}

public class TestConstructorReference {

	public static void main(String[] args) {	
		
		//*** Using Lambda Expression ***//
		C c1 = () -> new Employee();
		c1.getEmployee().getInfo();
		D d1 = (name,age) -> new Employee(name,age);
		d1.getEmployee("Tony", 34).getInfo();
		
		//*** Using Method Reference ***//
		C c2 = Employee::new;
		c2.getEmployee().getInfo();
		D d2 = Employee::new;
		d2.getEmployee("Tony", 34).getInfo();
	}
}

 

In the above code snippet, we have two Functional interfaces C & D. Interface C has abstract method with no arguments whereas D has with arguments. We will have same constructor reference code in both cases as shown in the highlighted lines of code. Also, if you run the code in your development environment, you will get the same output in each case.

Example of Reference to an Instance Method of an Arbitrary Object of a Particular Type

This type of Instance methods refers to a non-static method that are not bound to a receiver object. In this case we don’t need to create an object of a particular type.

public class TestArbitraryObjectMethodReference {

	public static void main(String[] args) {	
		
		List<Integer> numbers = Arrays.asList(15, 33, 59, 24, 40, 2, 19, 25,60);
		
		//*** Using Anonymous Inner class ***//
		Collections.sort(numbers, new Comparator<Integer>() {
			public int compare(Integer i1,Integer i2) {
				return i1.compareTo(i2);
			}
		});
		System.out.println("************* Using Anonymous Inner class ***************");
		numbers.forEach(System.out::println);
		
		//*** Using Lambda Expression ***//
		System.out.println("************* Using Lambda Expression *******************");
		Collections.sort(numbers,(i1,i2) ->i1.compareTo(i2));
		numbers.forEach(System.out::println);
		
		//*** Using Method Reference ***//
		System.out.println("************* Using Method reference ********************");
		Collections.sort(numbers,(Integer::compareTo));
		numbers.forEach(System.out::println);
	}
}

In the above code snippet we have shown the three ways to implement a Functional Interface (Comparator) simultaneously. Of course, All of them outputs the same result.

Difference between reference to an Instance method of a particular object & an arbitrary Object of a given type 

You might have some doubt on difference between both references, so now it’s right time to talk about them. To illustrate, let’s observe the examples given in the table below. I am sure you will get the clear idea on differences. There is no need to explain more about this.

Method reference Examples of Particular Object Vs an Arbitrary Object

 

Reference to super class & child class method using super & this keyword

Now we will see the use of super & this keyword in writing Method references accordingly.

interface A {
	public void sayHello();
}

class SuperClass {
	public void superHello(){
		System.out.println("I am inside SuperTest class");
	}
}

class ChildClass extends SuperClass{
	
	public void childHello() {
		System.out.println("I am inside SubTest class");
	}
	
	public void testHello() {
		
		//***Using Method reference :super class method***//
		A a1= super::superHello;
		a1.sayHello();
		
		//***Using Lambda Expression :super class method***//
		A a3= () -> System.out.println("I am inside SuperTest class");
		a3.sayHello(); 
		
		//***Using Method reference :current class method***//
		A a2= this::childHello;
		a2.sayHello();
		
		//***Using Lambda Expression :current class method***//
		A a4= () -> System.out.println("I am inside SubTest class");
		a4.sayHello();
	}
}

public class Test {

	public static void main(String[] args) {	
		
		ChildClass t = new ChildClass();
		t.testHello();
	}
}

As in the above code snippet, we have a functional interface ‘A‘ with Single Abstract method sayHello(). We have two classes SuperClass & ChildClass. Existing methods superHello() & childHello() are referred to write method references using super & this keyword respectively.

Furthermore, If you want to learn more about Method Reference(::) Java 8, kindly visit official Oracle Documentation.

You’ve been successfully subscribed to our newsletter!

2 thoughts on “Method Reference(::) Java 8”

  1. Section “Method reference to an Instance method of a class :” is incomplete, you forgot to add Functional Interface B;
    interface B{
    void add(int x, int y);
    }

Leave a Reply

Your email address will not be published.