Java 8 mang lại cho chúng ta khá nhiều tính năng mới. Trong bài viết trước đó tôi đã có đề cập đến tính năng đầu tiên là Lambda Expressions. Để tiếp tục chia sẻ kiến thức cùng mọi người, trong bài viết này tôi sẽ giải thích chi tiết nhất có thể để mọi người cùng tìm hiểu về Method References trong vòng 5 phút.
Java 8 - Tìm hiểu Method References trong 5 phút

Method References là gì?

Nó là một tính năng khá hay và liên quan đến việc sử dụng Lambda Expression. Nó làm cho việc viết code của bạn trở nên đơn giản hơn rất nhiều và nhìn chúng đẹp hơn. Method References cho phép chúng ta tham chiếu đến các constructor hoặc method mà không cần thực thi chúng.

Các kiểu Method Reference

Chúng ta có 4 kiểu tham chiếu phương thức và bạn có thể tham khảo nó từ bảng bên dưới đây.
Type Example Syntax
1. Tham chiếu đến một static method ContainingClass::staticMethodName Class::staticMethodName
2. Tham chiếu đến một constuctor ClassName::new ClassName::new
3. Tham chiếu đến một instance method của một đối tượng tùy ý của một kiểu cụ thể ContainingType::methodName Class::instanceMethodName
4. Tham chiếu đến một instance method của một đối tượng cụ thể containingObject::instanceMethodName object::instanceMethodName

Như vậy là chúng ta vừa biết được các syntax để sử dụng tham chiếu phương thức rồi đúng không nào. Nhưng để làm cho nó dễ hiểu và nắm bắt kỹ hơn thì dưới đây mình sẽ demo thêm một số ví dụ để các bạn xem nhé.

1. Tham chiếu đến một static method

import java.util.List;

public class ReferenceToStaticMethodExample {
  public static void main (String... args) {
    List names = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
    names.forEach(ReferenceToStaticMethodExample::printOddNumber);
  }

  /* In các số lẻ ra màn hình */
  public static void printOddNumber(int number) {
    if (number % 2 == 1) {
      System.out.println(number);
    }
  }

}

Trong ví dụ trên bạn có thể thấy rằng chúng ta vừa sử dụng tham chiếu đến một static method, cụ thể ở đây là ReferenceToStaticMethodExample::printOddNumber.
Containing classReferenceToStaticMethodExample
staticMethodNameprintOddNumber

2. Tham chiếu đến constructor

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

public class Demo {
  public static void main(String[] args) {
    List<String> digits = Arrays.asList("1", "2", "3", "4", "5");
    List<Integer> numbers = convertToInteger(Integer::new, digits);
    numbers.forEach(System.out::println);
  }

  static <T, R> List<R> convertToInteger(Function<T, R> function, List<T> source) {
    List<R> destiny = new ArrayList<>();
    for (T item : source) {
      R value = function.apply(item);
      destiny.add(value);
    }
    return destiny;
  }
}
Nó khá giống với việc bạn tham chiếu đến một phương thức static. Điểm khác biệt ở đây là bạn đang tham chiếu đến constructor sử dụng từ khóa new với syntax ClassName::new.
ClassNameInteger
newnew

3. Tham chiếu đến một instance method của một đối tượng tùy ý của một kiểu cụ thể

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

public class ReferenceToInstanceMethodAOPT {
  public static void main(String[] args) {
    List<Student> persons = new ArrayList<>();
    persons.add(new Student("Albert", 18));
    persons.add(new Student("Ben", 15));
    persons.add(new Student("Charlote", 16));
    persons.add(new Student("Dean", 16));
    persons.add(new Student("Elaine", 17));

    List<Integer> allAges = getAges(persons, Student::getAge);
    System.out.println("Printing out all ages \n" + getAges);
  }

  static List<Integer> getAges(List<Student> person, Function<Student, Integer> f) {
    List<Integer> ages = new ArrayList<>();
    person.forEach(x -> ages.add(f.apply(x)));
    return ages;
  }

  static class Student {
    private final String name;
    private final int age;

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

    }

    public String getName() {
      return name;
    }

    public int getAge() {
      return age;
    }
  }
}
Trong ví dụ này bạn có thể thấy rằng chúng ta đang tham chiếu đến bất kỳ đối tượng trong danh sách students của một kiểu cụ thể là Student và tên của phương thức được tham chiếu là getAge();

ContainingTypeStudent
methodNamegetAge

4. Tham chiếu đến một instance method của một đối tượng cụ thể

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

public class Demo {
  public static void main(String[] args) {
    List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
    findOddNumber(numbers, System.out::println);
  }

  static void findOddNumber(List<Integer> numbers, Consumer<Integer> consumer) {
    for (Integer number : numbers) {
      if (number % 2 == 1) {
        consumer.accept(number);
      }
    }
  }
}
Trong ví dụ trên, System.out là một instance của PrintStream và chúng ta đang gọi phương thức println của instance này bằng syntax containingObject::instanceMethodName

containingObjectSystem.out
methodNameprintln

Tóm lại

  1. Bạn có thể sử dụng Method References để thay thế cho các Lambda Expression khi Lambd gọi một phương thức nào đó đã được định nghĩa sẵn
  2. Bạn không thể truyền tham số cho các Method References. Trong ví dụ các bạn cũng đã thấy vấn đề này và chúng ta phải sử dụng đi kèm với Consumer, Function
Hi vọng rằng bài viết này có thể giúp bạn bổ sung thêm kiến thức về Java 8 trong 5 phút ngắn ngủi, chúc các bạn học tốt và ứng dụng vào công việc của mình.