Các dạng implementation của functional interface

Trong bài viết trước, chúng ta đã tìm hiểu về Functional interface và phải phân biệt rõ ràng giữa Functional interface và implementation của nó. Lý do là vì Functional interface có duy nhất một loại, chỉ cần lấy ra và sử dụng. Tuy nhiên, mỗi implementation của nó lại có nhiều dạng khác nhau. Vậy hãy tiếp tục đọc bài viết để tìm hiểu về những dạng implementation đó.

1. Chuẩn bị vài thứ

Trước tiên, để làm rõ điều này, chúng ta sẽ chuẩn bị sẵn một đoạn code mẫu. Đầu tiên, hãy xem xét một functional interface như sau:

@FunctionalInterface 
public interface Flyable {
    void fly();
}

Sau đó, chúng ta cần một phương thức sử dụng functional interface trên, cũng có nghĩa là phương thức này sẽ chấp nhận một phương thức khác có dạng void fly().

public void tryFlying(Flyable somethingCanFly) {
    somethingCanFly.fly();
}

Sau khi chuẩn bị như vậy, chúng ta sẵn sàng tiến đến bước tiếp theo, “bay”. Và trong ví dụ này, chúng ta sẽ sử dụng 4 cách bay khác nhau, bao gồm “gà bay”, “chim bay” và “máy bay”. Mỗi loại bay chỉ đơn giản là in ra màn hình dòng chữ thôi.

2. Implementation bằng class (cách truyền thống)

Hai cách thực hiện implementation truyền thống (tức là trước Java 8) là sử dụng class và anonymous class.

2.1. Sử dụng class riêng biệt

Cách đơn giản nhất là tạo một class mới, implement interface Flyable. Khi đó, đối tượng của class này hoàn toàn có thể được truyền vào phương thức tryFlying().

public class Chicken implements Flyable {
    @Override
    public void fly() {
        // Mã implementation ở đây
        System.out.println("Gà đang bay...");
    }
}

Sau đó, chúng ta có thể thực hiện như sau:

tryFlying(new Chicken());

2.2. Sử dụng anonymous class

Nếu bạn không muốn tạo thêm class, có thể sử dụng anonymous class như sau:

Flyable chicken = new Flyable() {
    @Override
    public void fly() {
        // Mã implementation ở đây
        System.out.println("Gà đang bay...");
    }
};

tryFlying(chicken);

// Hoặc cùng khởi tạo trong một dòng
tryFlying(new Flyable() {
    @Override
    public void fly() {
        // Mã implementation ở đây
        System.out.println("Gà đang bay...");
    }
});

Tuy nhiên, hai cách này có vẻ dài dòng và khi sử dụng nhiều thì sẽ làm chậm chương trình (do tạo ra nhiều class không cần thiết).

3. Java 8, chỉ cần sử dụng lambda

Java 8 giới thiệu thêm hai cách mới để viết implementation cho functional interface một cách nhanh gọn và đẹp hơn.

3.1. Lambda

Đầu tiên, chúng ta sẽ tìm hiểu về lambda. Dưới đây là một ví dụ:

Flyable bird = () -> System.out.println("Chim đang bay...");
tryFlying(bird);

// Hoặc viết ngắn gọn hơn
tryFlying(() -> System.out.println("Chim đang bay..."));

Nhìn quen không? Lambda giống như JavaSript arrow function hoặc tương tự anonymous class. Tuy nhiên, lambda không giống anonymous class về cách hoạt động bên trong.

Bạn có nhận ra sự tương quan giữa lambda và functional interface chưa?

Đơn giản như sau, lambda giống như một hàm rút gọn, có tham số và phần thân chứa mã code. Cú pháp của lambda hoàn toàn giống với phương thức fly() bên trong functional interface Flyable. Do đó, lambda là một implementation hợp lệ cho Flyable.

Vì thế, giờ bạn đã hiểu tại sao chúng ta sử dụng functional interface, không phải là interface thông thường. Đó là vì functional interface chỉ có một phương thức trừu tượng duy nhất. Nếu có nhiều phương thức trừu tượng khác, thì lambda sẽ là phương thức trừu tượng nào? Và những phương thức trừu tượng khác thì sao? Nếu không được ghi đè và vẫn được gọi, chắc chắn sẽ gây lỗi. Đó chính là lý do tại sao chúng ta sử dụng functional interface.

3.2. Method reference

Nếu bạn đã có một phương thức sẵn có (phù hợp với Flyable) và muốn truyền phương thức đó vào phương thức tryFlying(), thì bạn nên sử dụng method reference.

class Airport {
    // Đây là phương thức có sẵn, dùng làm implementation ngay lập tức
    public static void takeOffAPlane() {
        System.out.println("Máy bay đang bay...");
    }
}

// Thực hiện truyền method reference
tryFlying(Airport::takeOffAPlane);

// Có vài dạng method reference khác

Lambda và method reference là hai khái niệm không được đề cập kỹ trong bài viết này. Vì vậy, chỉ đơn giản là giới thiệu 4 dạng implementation của functional interface. Trong những bài tiếp theo, chúng ta sẽ tìm hiểu chi tiết hơn về chúng.

Kết luận

Trong bài viết này, chúng ta đã tìm hiểu về các dạng implementation của functional interface. Có thể nói đơn giản là cách đưa code vào trong một phương thức khác. Hi vọng mọi người đã hiểu và thấy hữu ích thông qua bài viết này. Chân thành cảm ơn mọi người đã dành thời gian đọc bài viết. Chúc mọi người thành công!

Ảnh được lấy từ source

Ảnh: alttext

FEATURED TOPIC