Java - Instance Method References Unbound Receiver

Introduction

For an unbound receiver, use the ClassName::instanceMethod syntax.

The lambda expression takes a Person as an argument and returns a String:

Function<Person, String> fNameFunc = (Person p) -> p.getFirstName();

This statement can be rewritten using the instance method reference as:

Function<Person, String> fNameFunc = Person::getFirstName;

The code above is confusing. Is it using a method reference to a static method? What is the receiver object of the instance method invocation?

If the method is an instance method, the method reference represents an instance method reference.

The first argument to the function by the target type is the receiver of the method invocation.

For the following code

Function<String, Integer> strLengthFunc = String::length;

String name ="abc";

// name is the receiver of String::length
int len = strLengthFunc.apply(name);
System.out.println("name = " + name + ", length = " + len);

Output

name = abc, length = 3

Example

The String instance method concat() has the following declaration:

String concat(String str)

The method reference String::concat represents an instance method reference for a target type whose function takes two String arguments and returns a String.

The first argument will be the receiver of the concat() method and the second argument will be passed to the concat() method.

Demo

import java.util.function.BiFunction;

public class Main {
  public static void main(String[] args) {
    String greeting = "Hello";
    String name = " Book2s.com";

    // Uses a lambda expression
    BiFunction<String, String, String> func1 = (s1, s2) -> s1.concat(s2);
    System.out.println(func1.apply(greeting, name));

    // Uses an instance method reference on an unbound receiver
    BiFunction<String, String, String> func2 = String::concat;
    System.out.println(func2.apply(greeting, name));
  }/*from  w  ww . j  a v  a  2 s . com*/
}

Result

The method reference Person::getFirstName that is an instance method reference on an unbound receiver.

List<Person> personList = Person.getPersons();

// Maps each Person object to its first name
List<String> firstNameList = FunctionUtil.map(personList, Person::getFirstName);

// Prints the first name list
forEach(firstNameList, System.out::println);

Demo

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;

public class Main {
  public static void main(String[] args) {
    List<Person> personList = Person.getPersons();

    // Maps each Person object to its first name
    List<String> firstNameList = map(personList, Person::getFirstName);

    // Prints the first name list
    forEach(firstNameList, System.out::println);

  } // Maps each item in a list to a value

  public static <T, R> List<R> map(List<T> list, Function<? super T, R> mapper) {
    List<R> mappedList = new ArrayList<>();
    for (T item : list) {
      mappedList.add(mapper.apply(item));

    }//from  w w  w.  ja v  a  2 s  .  c  om
    return mappedList;
  }

  // Applies an action on each item in a list
  public static <T> void forEach(List<T> list, Consumer<? super T> action) {
    for (T item : list) {
      action.accept(item);
    }
  }
}

enum Gender {
  MALE, FEMALE
}

class Person {
  private String firstName;
  private String lastName;
  private LocalDate dob;
  private Gender gender;

  public Person(String firstName, String lastName, LocalDate dob, Gender gender) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.dob = dob;
    this.gender = gender;
  }

  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 LocalDate getDob() {
    return dob;
  }

  public void setDob(LocalDate dob) {
    this.dob = dob;
  }

  public Gender getGender() {
    return gender;
  }

  public void setGender(Gender gender) {
    this.gender = gender;
  }

  @Override
  public String toString() {
    return firstName + " " + lastName + ", " + gender + ", " + dob;
  }

  // A utility method
  public static List<Person> getPersons() {
    ArrayList<Person> list = new ArrayList<>();
    list.add(new Person("A", "D", LocalDate.of(1975, 1, 20), Gender.MALE));
    list.add(new Person("B", "E", LocalDate.of(1965, 9, 12), Gender.MALE));
    list.add(new Person("C", "D", LocalDate.of(1970, 9, 12), Gender.FEMALE));
    return list;
  }
}

Result

Related Topic