Java 8 Tutorial: Method Reference
Đi cùng với Lambda Expression, Java 8 có thêm một khái niệm mới là Method Reference. Chúng ta thường dùng Lambda Expression để tạo ra các method vô danh (anonymous method), nhưng đôi lúc Lambda Expression cũng có thể tham chiếu đến các phương thức có sẵn để thực thi. Tất nhiên là phương thức đó phải có các tham số đầu vào và kiểu trả về tương ứng với Lambda Expression.
Việc tham chiếu đến các phương thức có sẵn được thực hiện qua toán tử “::“. Hãy xem một ví dụ dưới đây.
Sử dụng Lambda expression để sort 1 arraylist
import java.util.ArrayList;
import java.util.List;
public class MethodReference {
public static void main(String[] args) {
// Initialize an array
List arr = new ArrayList();
arr.add(3);
arr.add(4);
arr.add(5);
arr.add(1);
arr.add(2);
// Sort array using Lambda Expression
arr.sort((x, y) -> {return (x y) ? 1 : 0);});
// Print out
arr.forEach((x) -> System.out.println(x));
}
}
Thay vì phải định nghĩa ra Lambda Expression, nếu chúng ta đã có sẵn 1 Comparator thì vẫn có thể dùng lại được.
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class MethodReference {
public static void main(String[] args) {
// Initialize an array
List arr = new ArrayList();
arr.add(3);
arr.add(4);
arr.add(5);
arr.add(1);
arr.add(2);
// Sort array using Lambda Expression
arr.sort(MethodReference::compare);
// Print out
arr.forEach((x) -> System.out.println(x));
}
// Existing comparison logic
// This method has the same signature
// with method compare in Comparator class which is a Functional Interface
// and is applied as a parameter in List.sort method
public static int compare(Integer x, Integer y) {
return (x y) ? 1 : 0);
}
}
Lambda Expression đã tham chiếu đến hàm static compare trong lớp MethodReference để định nghĩa logic sort qua câu lệnh
MethodReference::compare
Hàm compare này có cú pháp giống như hàm compare trong interface Comparator. Comparator là 1 Functional Interface vì nó chỉ có duy nhất 1 hàm abstract là compare. Phương thức List.sort nhận vào 1 đối số là Lambda Expression đại diện cho interface Comparator. Vì vậy bất kỳ phương thức nào có cùng cú pháp giống như hàm compare đều được chấp nhận.
Ở ví dụ trên chúng ta dùng static method reference. Trong Java 8 hỗ trợ 4 kiểu reference là:
- Reference to a static method
- Reference to an instance method of a particular object
- Reference to an instance method of an arbitrary object of a particular type
- Reference to a constructor
Reference to an instance method of a particular object
Ví dụ đơn giản nhất cho kiểu reference này như sau:
package com.edward.tutorial.java8.test;
import java.util.ArrayList;
import java.util.List;
public class Test {
/**
* @param Main method
*/
public static void main(String[] args) {
// Initialize array
List arr = new ArrayList();
arr.add(1);
arr.add(4);
arr.add(3);
arr.add(2);
// Sort it
arr.sort((x, y) -> (x > y) ? 1 : (x < y) ? -1 : 0);
// Check it
arr.forEach(System.out::println);
}
}
Ở trên, đoạn in ra các phần tử trong array, chúng ta truyền vào 1 Lambda exrepssion tham chiếu đến method println của object out trong lớp System. Nếu viết theo cú pháp Lambda thông thường sẽ như sau:
arr.forEach((x) -> System.out.println(x));
Nghĩa là Lambda expression nhận vào 1 tham số x, và hàm println cũng nhận vào 1 tham số x, vậy có thể thay biểu thức Lambda bằng hàm println đó.
Reference to an instance method of an arbitrary object of a particular type
Hãy xem ví dụ dưới:
String[] stringArray = { "Barbara", "James", "Mary", "John",
"Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, (x, y) -> { return x.compareToIgnoreCase(y);});
Biến số x ở đây sẽ gọi hàm compareToIgnoreCase, vì vậy chúng ta có thể giản lược x và thay thế bằng method reference như sau:
Arrays.sort(stringArray, String::compareToIgnoreCase);
Reference to a constructor
Tôi sử dụng lại ví dụ trong bài viết Optional kỳ trước. Các bạn có thể đọc bài viết tại đây
Việc thực hiện hàm Optional.orElseThrow được thực hiện như sau:
// Edward
try {
System.out.println(name.orElseThrow(() -> {return new Exception();})); // Lambda expression
} catch (Exception e) {
e.printStackTrace();
}
// Cannot get object from emptyOptional
try {
// It will throw Exception
System.out.println(emptyOptional.orElseThrow(Exception::new)); // Here is also lambda expression, both are the same
} catch (Exception e) {
// Catch it
System.out.println("Cannot get object from emptyOptional");
e.printStackTrace();
}
Các bạn chỉ cần đến phần tham số truyền vào trong hàm orElseThrow
orElseThrow(() -> {return new Exception();})
orElseThrow(Exception::new)
Biểu thức Lambda không nhận vào đối số nào và trả về 1 đối tượng Expcetion. Điều đó tương đồng với hàm new để khởi tạo 1 đối tượng Exception. Nên ta có thể viết theo cả 2 cách trên.
Kết thúc bài giới thiệu về Method Reference trong Java 8 tại đây. Mình rất vui nếu có thể nhận được các đóng góp các ý kiến phản hồi bằng cách comment bên dưới bài viết. Các bạn có thể tham khảo một số bài viết khác trong series Java 8 Tutorial tại đây:
Series Java Core Overview
2 thoughts on “Java 8 Tutorial: Method Reference”