Java Method Reference

Method reference is supported in Java 8. A method reference is described using :: (double colon) symbol.

Types of Method Reference
There are four types of method references:

  1. A method reference to a static method.
  2. A method reference to an instance method of an object of a particular type.
  3. A method reference to an instance method of an existing object.
  4. A method reference to a constructor.

Static Method Reference

Notice that below code between System.out and println, the :: operator is used instead of the . operator. And we don't pass arguments to the method reference. So, you can refer to static method defined in the class with interfaces that contain only one abstract method in addition to one or more default or static methods.

Consumer<?> is a functional interface. Lambda expression and Static method references that implement Consumer<String> functional interface are passed to the accept() method to be executed. Actually, Lambda expression  can be replaced with Method reference.

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class Program {
    public static void main(String[] args) {
        List<String> names = Arrays.asList("name1", "name2", "name3", "name4");


        //1. way: using Anonymous Inner Class
        Consumer<String> action1 = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };

        names.forEach(action1);

        System.out.println("*******************");

        //2. way: using Lambda Expression
        Consumer<String> action2 = (x) -> System.out.println(x);

        names.forEach(action2);

        System.out.println("*******************");


        //3. way: using Static Method Reference
        Consumer<String> action3 = System.out::println;

        names.forEach(action3);

        System.out.println("*******************");


        //4. way: pass Lambda Expression as argument
        names.forEach((x) -> System.out.println(x));


        System.out.println("*******************");


        //5. way: pass Static Method Reference as argument
        names.forEach(System.out::println);

    }
}

Output:

name1
name2
name3
name4
*******************
name1
name2
name3
name4
*******************
name1
name2
name3
name4
*******************
name1
name2
name3
name4

Constructor Method Reference

In order to create a new object, you can refer to a constructor of class with the keyword new. If the constructor doesn't have any arguments, Supplier Functional interface can be used. If the constructor takes an argument, Function interface can be used. Lastly, if the constructor takes more than three arguments, you should create your own Functional interface.

import java.util.function.Supplier;

public class Program {

	public static void main(String[] args) {
		Supplier constructorRef1 = Person::new;

		Person person1 = constructorRef1.get();
		person1.setFirstName("Kenan");
		person1.setLastName("Hancer");
		person1.setAge(33);

		// Constructor Method Reference
		PersonConstructorWithParameters constructorRef2 = Person::new;

		Person person2 = constructorRef2.get("Enes", "Hancer", 4);

		// Constructor Method Reference
		ConstructorWithThreeParameters<String, String, Integer, Person> constructorRef3 = Person::new;

		Person person3 = constructorRef3.get("Kenan", "Hancer", 33);

		// Lambda Expression
		Supplier personSupplier1 = () -> new Person();

		Person person4 = personSupplier1.get();

		// Anonymous Inner Class
		Supplier personSupplier2 = new Supplier() {

			public Person get() {
				return new Person();
			}
		};

		Person person5 = personSupplier2.get();

		// Constructor Method Reference
		ConstructorWithThreeParameters<String, String, String, Customer> constructorRef4 = Customer::new;

		Customer customer1 = constructorRef4.get("Istanbul", "1110033", "kh@kh.com");

		// Instance Method Reference
		Supplier getStringValueRef = person1::getFirstName;

		String firstName = getStringValueRef.get();

		// Instance Method Reference
		getStringValueRef = person1::getLastName;

		String lastName = getStringValueRef.get();

		System.out.printf("%s %s", firstName, lastName);

	}

}

interface PersonConstructorWithParameters {
	Person get(String firstName, String lastName, int age);
}

interface ConstructorWithThreeParameters<P1, P2, P3, R> {
	R get(P1 p1, P2 p2, P3 p3);
}

class Person {
	String firstName;
	String lastName;
	int age;

	public Person() {
	}

	public Person(String firstName, String lastName, int age) {
		this.firstName = firstName;
		this.lastName = lastName;
		this.age = age;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}

class Customer {
	String address;
	String phone;
	String email;

	public Customer(String address, String phone, String email) {
		this.address = address;
		this.phone = phone;
		this.email = email;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}
}

 

 

Example 1

interface Action{
    void invoke();
}

interface ActionV2{
    void invoke(String name);
}


public class Program {
    public static void main(String[] args) {

        Action action1 = Program::sayHello;

        ActionV2 action2 = Program::sayHello;


        action1.invoke();

        action2.invoke("Kenan");
    }

    private static void sayHello(){
        System.out.println("Hello");
    }

    private static void sayHello(String name){
        System.out.println("Hello " + name);
    }
}

Output:

Hello
Hello Kenan

Example 2

import java.util.function.Consumer;

public class Program {
    public static void main(String[] args) {

        Runnable action1 = Program::sayHello;

        Consumer<String> action2 = Program::sayHello;


        action1.run();

        action2.accept("Kenan");
    }

    private static void sayHello(){
        System.out.println("Hello");
    }

    private static void sayHello(String name){
        System.out.println("Hello " + name);
    }
}

Output:

Hello
Hello Kenan

Example 3

import java.util.function.BiFunction;

public class Program {
    public static void main(String[] args) {

        BiFunction<Integer, Integer, Integer> addReference = Program::add;

        BiFunction<Integer, Integer, Integer> subtractReference = Program::subtract;

        BiFunction<Integer, Integer, Integer> multiplyReference = Program::multiply;

        BiFunction<Integer, Integer, Double> divideReference = Program::divide;


        int addResult = addReference.apply(6, 4);

        int subtractResult = subtractReference.apply(10, 2);

        int multiplyResult = multiplyReference.apply(5, 5);

        double divideResult = divideReference.apply(20, 2);

        System.out.println("add result is " + addResult);

        System.out.println("subtract result is " + subtractResult);

        System.out.println("multiply result is " + multiplyResult);

        System.out.println("divide result is " + divideResult);

    }

    private static int add(int a, int b) {
        return a + b;
    }

    private static int subtract(int a, int b) {
        return a - b;
    }

    private static int multiply(int a, int b) {
        return a * b;
    }

    private static double divide(int a, int b) {
        return a / b;
    }
}

Output:

add result is 10
subtract result is 8
multiply result is 25
divide result is 10.0

Example 4

import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

public class Program {
    public static void main(String[] args) {
        ConstructorReference<Person> constructor = Person::new;

        Person person1 = constructor.invoke("Kenan");

        Supplier<Person> personFactory = Person::new;

        Person person2 = personFactory.get();

        Function<String, Person> personConstructorDelegate = Person::new;

        Person person3 = personConstructorDelegate.apply("ENES");

        MethodReference method = Person::method;

        method.invoke("Test");

        MethodReference method2 = person2::nextMethod;

        method2.invoke("Test2");

        Consumer<String> method3 = Person::method;

        method3.accept("Test3");

        Consumer<String> c1 = s -> System.out.println(s);

        c1.accept("Test4");

        Consumer<String> c2 = System.out::println;

        c2.accept("Test5");

        Runnable runnable = Program::printMessage;

        Thread t1 = new Thread(runnable);

        t1.start();

        new Thread(Program::printMessage).start();

        BiFunction<Integer, Integer, Integer> addDelegate = Program::add;

        int r1 = addDelegate.apply(4, 5);
    }

    private static void printMessage() {
        System.out.println("Hello world");
    }

    private static int add(int a, int b) {
        return a + b;
    }
}

class Numbers {
    private Numbers() {
    }

    public static boolean isMoreThanFifty(int n1, int n2) {
        return (n1 + n2) > 50;
    }

}

class Person {
    public Person() {
    }

    public Person(String name) {
    }

    public static void method(String input) {
        System.out.println(input);
    }

    public void nextMethod(String input) {
        System.out.println(input);
    }
}

interface ConstructorReference<T> {
    T invoke(String name);
}

interface MethodReference {
    void invoke(String input);
}

Example 5
Reference to a constructor

import java.util.function.Supplier;

public class Program {
    public static void main(String[] args) {
        Supplier<Person> constructorRef1 = Person::new;

        PersonConstructorWithParameters constructorRef2 = Person::new;


        Person person1 = constructorRef1.get();

        person1.setFirstName("Enes");

        person1.setLastName("Hancer");

        person1.setAge(4);


        Supplier<String> getFirstNameRef = person1::getFirstName;

        Supplier<String> getLastNameRef = person1::getLastName;


        String firstName = getFirstNameRef.get();

        String lastName = getLastNameRef.get();

        System.out.println(firstName + " " + lastName);

        


        Person person2 = constructorRef2.get("Kenan", "Hancer", 33);


        getFirstNameRef = person2::getFirstName;

        getLastNameRef = person2::getLastName;


        firstName = getFirstNameRef.get();

        lastName = getLastNameRef.get();

        System.out.println(firstName + " " + lastName);
    }
}

interface PersonConstructorWithParameters {
    Person get(String firstName, String lastName, int age);
}

class Person {
    String firstName;
    String lastName;
    int age;

    public Person() {
    }

    public Person(String firstName, String lastName, int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Output:

Enes Hancer
Kenan Hancer

Leave a Reply