What are method references in Java8?

Method references are a java8 feature that enables you to do this; they are compact, easy-to-read lambda expressions for methods that already have a name.

We use lambda expressions to create anonymous methods. Sometimes, however, a lambda expression does nothing but call an existing method.

In those cases, it’s often clearer to refer to the existing method by name.

To achieve this we need to use the double-colon notation to separate an instance reference or class name from the

method.((("
(double colon) notation in method references")))

If a lambda expression is essentially treating a method as though it was an object, then a method reference treats an existing method as though it was a lambda.

the forEach method in Iterable takes a Consumer as an argument.
in the below example, the Consumer can be implemented as either a lambda expression or as a method reference.

Using a lambda expression

Stream.of(7, 12, 11, 21, 8, 5)
.forEach(x -> System.out.println(x));

Using a method reference

Stream.of(7, 12, 11, 21, 8, 5)
.forEach(System.out::println);

If you write a lambda expression that consists of one line that
invokes a method, consider using the equivalent method reference
instead.

Method reference advantages over the lambda

  • It can be written in a short code.
  • It includes the name of the class containing the method.
  • Method references can be used with static methods as well.

Use of method reference for different types of method

Stream.generate(Math::random) //Static method
.limit(10)
.forEach(System.out::println); //Instance method

The generate method on Stream takes a Supplier as an argument, which is a functional interface whose single abstract method takes no arguments and produces a single result.

The random method in the Math class is compatible with that signature,
because it also takes no arguments and produces a single, uniformly distributed,
pseudorandom double between 0 and 1.

The method reference Math::random refers
to that method as the implementation of the Supplier interface.

Stream.generate produces an infinite stream, the limit method is used to
ensure only 10 values are produced, which are then printed to standard output using
the System.out::println method reference as an implementation of Consumer.

Assigning the method reference to a functional interface

Consumer<Integer> printer = System.out::println;
Stream.of(7, 12, 11, 21, 8, 5)
.forEach(printer);

The double-colon notation provides the reference to the println method on the
System.out instance, which is a reference of type PrintStream. No parentheses are
placed at the end of the method reference. In the example shown, each element of the
stream is printed to standard output.

Types of Method References

There are three types of method references that are as follows:

  • Static Method Reference.
  • Instance Method Reference of a particular object
  • Instance Method Reference of an arbitrary object of a particular type.

Static Method Reference.

Class::staticMethod

// equivalent to Math::max
(x,y) -> Math.max(x,y)

Refer to the static method, as in Math::max

Java Program to demonstrate use of Static method reference

package com.asyncster.java.program.examples.basic.java8;
// Java Program to to demostrate use of Static method reference

// To Sort with Custom Comparator

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

class User {

	private String name;
	private Integer age;

	public User(String name, int age) {
		this.name = name;
		this.age = age;
	}

	// Getter-setters
	public Integer getAge() {
		return age;
	}

	public String getName() {
		return name;
	}
}

public class StaticMethodReferenceMain {

	// Static method to compare with name
	public static int compareByName(User user1, User user2) {
		return user1.getName().compareTo(user2.getName());
	}

	// Static method to compare with age
	public static int compareByAge(User a, User b) {
		return a.getAge().compareTo(b.getAge());
	}

	public static void main(String[] args) {

		List<User> UserList = new ArrayList<>();

		UserList.add(new User("Sara", 16));
		UserList.add(new User("Joseph", 24));
		UserList.add(new User("Jonathan", 21));
		UserList.add(new User("Maya", 22));

		// Using static method reference to
		// sort array by name
		Collections.sort(UserList, StaticMethodReferenceMain::compareByName);

		 
		System.out.println("Sort by User Name :");

		// Using streams over above object of User type
		UserList.stream().map(x -> x.getName()).forEach(System.out::println);

		System.out.println("============================================");
		System.out.println("Sort by User Age :");
		
		Collections.sort(UserList, StaticMethodReferenceMain::compareByAge);

		// Using streams over above object of User type
		UserList.stream().map(x -> x.getName()).forEach(System.out::println);
	}
}
Sort by User Name :
Jonathan
Joseph
Maya
Sara
============================================
Sort by User Age :
Sara
Jonathan
Maya
Joseph

Instance Method Reference of a particular object

object::instanceMethod

Refer to an instance method using a reference to the supplied object, as in
System.out::println

// equivalent to String::length
x -> x.length()

Instance Method Reference of an arbitrary object of a particular type

Class::instanceMethod

Class::instanceMethod
Invoke the instance method on a reference to an object supplied by the context,
as in String::length

// equivalent to System.out::println
x -> System.out.println(x)

Invoking a multiple-argument instance method from a class reference

List<String> strings =
Arrays.asList("this", "is", "a", "list", "of", "strings");
List<String> sorted = strings.stream()
.sorted((s1, s2) -> s1.compareTo(s2))
.collect(Collectors.toList());

List<String> sorted = strings.stream()
.sorted(String::compareTo)
.collect(Collectors.toList());

In stream processing, you frequently access an instance method using the class name
in a method reference if you are processing a series of inputs.

length method on each individual String in the stream.

	Stream.of("this", "is", "a", "stream", "of", "strings").map(String::length).forEach(System.out::println);

Lambda expression equivalents for method

Stream.of("this", "is", "a", "stream", "of", "strings")
.map(s -> s.length())
.forEach(x -> System.out.println(x));

In this article, we have seen What is method References, the advantages of Method references over lambda, and different types of Method References with examples.

Method References in Java8 with examples
Tagged on:

Leave a Reply

Your email address will not be published. Required fields are marked *