HomeOur Team

Functional Interface trong Java 8 (Phần 1)

By manh.nguyen
Published in Solutions
December 06, 2022
3 min read

1. Functional interface là gì?

“Function Interface” là một trong các tính năng mới và quan trọng nhất của Java 8 để triển khai lập trình chức năng. Nó đại diện cho một hàm nhận một đối số và trả ra kết quả. Do đó, function interface có 2 tham số để đại diện như sau: 

  • T :  đại diện đối số đầu vào
  • R : đại diện kiểu trả về của hàm

Functional interface là có duy nhất 1 abstract method, có thể có nhiều static/default method hoặc không có. Trong đoạn code sau, ta có Flyable() là một functional interface

@FunctionalInterface
public interface Flyable {
void fly();
default boolean alive() {
return true;
}
}

Để nhận biết đây là một function interface, ta sử dụng @FunctionalInterface ở đầu interface. Chùng ta chỉ có duy nhất một abstract method nên nếu chúng ta khai báo nhiều hơn một abstract method trong intercae được đánh dấu annotation @FunctionalInterface thì sẽ bị báo lỗi ‘Unexpected @FunctionalInterface annotation’. Functional interface còn được gọi là SAM type (Single abstract method) vì đúng theo trên định nghĩa của nó.

2. Tại sao phải dùng Functional interface?

Với một số language như JavaScript, các function là first-class citizen, nghĩa là function là số 1, function có các “khả năng cấp cao” như làm đối số function khác, làm giá trị trả về, hàm lồng trong hàm khác,…

Do đó, hàm trong JavaScript rất linh hoạt, hỗ trợ rất tốt cho functional programming.

Quay lại với Java, thì method trong Java không linh hoạt như vậy, do Java xem class là first-class citizen chứ không phải function. Do đó, chúng ta không thể thực hiện các kĩ thuật nâng cao như JavaScript, điển hình là truyền function vào function khác (rất phổ biến trong functional programming).

function printResult(calculate) {
console.log('Result is', calculate())
}
printResult(function () {
return 3.14
})

Cách viết như trên, Java không thực hiện được. Method trong Java không thể truyền vào method khác dưới dạng đối số. Do đó, team Java đã nghĩ ra một cách tiếp cận khác để giải quyết vấn đề này.

3. Dùng Functional interface để wrap method

Sở dĩ Java không làm được như JavaScript, cũng một phần bởi vì Java khá strict, mọi thứ phải rõ ràng, trong khi JavaScript dynamic hơn. Ví dụ một function A nhận function B làm đối số, Java cần biết:

  • Function B trả về kiểu dữ liệu gì?
  • Function B có các tham số như thế nào?

Đó là còn chưa kể mọi method của Java phải ở trong class nào đó. Trong khi đó JavaScript chả quan tâm, không cần khai báo kiểu function luôn. Thêm nữa số lượng đối số truyền vào không cần đầy đủ, với JavaScript vẫn chạy ok hết.

Câu hỏi đặt ra là làm sao để vừa cho phép truyền function vào function, vừa giữ được tính chặt chẽ cho code.

Team Java đã quyết định sử dụng thứ gọi là Functional interface làm khuôn mẫu cho function, và kèm thêm các cách implementation phù hợp cho nó.

Hãy xem xét code Java sau, có thể thực hiện được việc truyền method (chỗ @Override) vào trong method printResult.

// Định nghĩa khuôn mẫu cho method truyền vô
@FunctionalInterface
interface Calculable {
double calculate();
}
...
// Có thể gọi được method trong khuôn mẫu
public void printResult(Calculable func) {
System.out.println("Result: " + func.calculate());
}
...
// Method thực sự truyền vào, được wrap vô trong khuôn mẫu
printResult(new Calculable() {
@Override
public double calculate() {
return 3.14;
}
})

Hơi dài dòng, nhưng khá dễ hiểu. Method nhận cần biết về “hình dạng” của method truyền vào để gọi cho đúng, và method truyền vào cần có “hình dạng” khớp với method kia. Và cái “hình dạng” đó chính là abstract method trong functional interface.

Thay vì truyền trực tiếp function B vào function A, thì phải “gói” function B vào một object (có dạng của functional interface).

Sau đó mới truyền object đó vào cho function A. Function A chỉ cần lấy ra và sử dụng thôi.

Đó là cách giúp cho Java thực hiện truyền method vào method khác. Hiểu được nguyên lý hoạt động này thì những kiến thức tiếp theo sẽ đơn giản hơn rất nhiều.

Và cũng nên phân biệt rạch ròi giữa functional interface (hình dạng method) và implementation của nó (code của method thực sự). Hình dạng được chỉ định bởi functional interface, nhưng implementation của nó có thể thực hiện bằng nhiều cách (tạo anonymous class như trên, dùng class riêng biệt, dùng lambda expression, method reference).


Bạn có thể thắc mắc, vậy dùng interface thường được không? Tại sao phải dùng functional interface, hay interface chỉ có mỗi một abstract method? Câu trả lời sẽ có trong bài tiếp theo nhé.


Tags

java 8

Share

manh.nguyen

manh.nguyen

Developer

Expertise

Related Posts

Solutions
Functional Interface trong Java 8 (Phần 2) - Cách triển khai
December 06, 2022
2 min
© 2023, All Rights Reserved.
Powered By

Quick Links

HomeOur Team

Social Media