Mastering Method References in Java 8

In certain scenarios a lambda expression does nothing but call an existing method of a class. In those cases, it's better to use the existing method by name and we can do that by using method references. We're going to use lambda expressions throughout this article and if you want a refresher on those I suggest you to read lambda expressions in java 8 article.

Let's use the already defined Employee class from lambda expressions post and create employee data for us to use in out custom defined functions.

Employee p1 = new Employee("Ally", Employee.Sex.FEMALE, "allbeal@me.com", 45);
Employee p2 = new Employee("Harris", Employee.Sex.MALE, "harrisClam@me.com", 26);
Employee p3 = new Employee("Clay", Employee.Sex.MALE, "claydubs@me.com", 42);
Employee p4 = new Employee("Britain", Employee.Sex.FEMALE, "britaing@me.com", 23);
List<Employee> employees = new ArrayList<>();
employees.add(p1);
employees.add(p2);
employees.add(p3);
employees.add(p4);

Employee[] empData = employees.toArray(new Employee[employees.size()]);

Suppose we want to sort employees based on their age. How do we do that? Let's create a comparator that sorts the employees by age.

class EmployeeAgeComparator implements Comparator<Employee> {
    public int compare(Employee a, Employee b){
        return Integer.compare(a.getAge(), b.getAge());
    }
}

We can sort employees by using our custom comparator EmployeeAgeComparator

Arrays.sort(empData, new EmployeeAgeComparator());

We've done nothing special until now. We just sorted employees data by age. Since, comparator is a functional interface we can use lambda expression.

// refactored to use lambda expressions
Arrays.sort(empData, (Employee a, Employee b) -> {return Integer.compare(a.getAge(), b.getAge())});

As we have the compareByAge method already defined, let's use that:

Arrays.sort(empData, (a, b) -> Employee.compareByAge(a, b));

Since the above function invokes an existing method, we can use method reference instead. There are four types of method references:

  1. Reference to a static method

    Arrays.sort(empData, Employee::compareByAge) // compareByAge is the static method.
  2. Reference to an instance method of a particular object

    Arrays.sort(empData, Employee::compareByName) // compareByName is the instance method.
  3. Reference to an instance method of an Arbitrary Object of a particular type

    // Created an array of String type.
    String[] stringArray = {"Clay", "Ally", "Britain", "Harris", "Zed"};
    Arrays.sort(stringArray, (String a, String b) -> a.compareToIgnoreCase(b));
    // instead of using lambda we can use method reference.
    Arrays.sort(stringArray, String::compareToIgnoreCase); // compareToIgnoreCase is the instance method
  4. Reference to a constructor

    // if the constructor takes no arguments, use Supplier interface
    Supplier> suppString = () -> new HashSet();
    // refactored to use method reference
    Supplier> refString = HashSet::new;
    
    // if the constructor takes an argument then use Function interface.
    Function funLambda = a -> new Integer(a);
    // refactored to use method reference
    Function funReference = Integer::new;
    
    // Similary if the constructor takes two arguments we can use BiFunction.
    BiFunction newEmployee = (name, email) -> new Employee(name, email);
    // Refactored to use method reference
    BiFunction refEmployee = Employee::new;

Writing clean code is very important and an elegant code goes a long way as it's a pleasure to read and easy to maintain. I sincerely hope that this post helped you in understanding method references in Java 8.](https://aakashsharan.com/categories/java/).

References: Method references oracle and Codementor Java8