Java

Java 8 Tutorial: Method Reference

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<Integer> arr = new ArrayList<Integer>();
		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 : ((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<Integer> arr = new ArrayList<Integer>();
		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 : ((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<Integer> arr = new ArrayList<Integer>();
		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 8 Tutorial

http://www.edwardthienhoang.wordpress.com

Advertisements

2 thoughts on “Java 8 Tutorial: Method Reference”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s