Java 8 cung cấp sẵn cho chúng ta rất nhiều Functional Interface và Function<T, R> là một trong số đó. Cũng giống như những functional interface khác, Function<T, R> có thể sử dụng cho lambda expression hoặc method reference như một nhiệm vụ mục tiêu. Nó bao gồm 4 phương thức sau:

Modifier & Type Method & Description
default <V> Function<T,V> andThen(Function<? super R,? extends V> after)
Kết quả trả về là một Function gộp mà nó đã áp dụng function lên dữ liệu đầu vào và sau đó áp dụng tiếp after function lên kết quả đầu ra.
R apply(T t)
Áp dụng function lên đối số đầu vào.
default <V> Function<V,R> compose(Function<? super V,? extends T> before)
Kết quả trả về là một function gộp mà nó đã áp dụng before Function lên đối số đầu vào, sau đó áp dụng function lên dữ liệu đầu ra.
static <T> Function<T,T> identity()
Kết quả trả về là một function luôn trả về đối số đầu vào của nó.
Trong bảng trên, tôi đã dịch từ tiếng anh sang tiếng việt và trông nó có vẻ khó hiểu. Nếu như bạn muốn nắm 1 cách rõ ràng hơn về lý thuyết thì có thể bấm vào đây để xem trên trang chủ Oracle.

Cách sử dụng Function

Đầu tiên chúng ta sẽ bắt đầu với phương thức apply trước. Như bạn đã biết thì khi làm việc với functional interface, chúng ta sẽ viết biểu thức lambda cho phần body code của phương thức. Dưới đây là 1 ví dụ minh họa về R apply(T t).
Function myFunction = (number) -> String.valueOf(number * 2);
String result = myFunction.apply(10);
System.out.println(result);
Trong đoạn code trên tôi đã tạo ra một Function với tên là myFunction.
- Đối số đầu vào là number có kiểu Integer
- Kết quả trả về là String.valueOf(number * 2) tương ứng với kiểu String.
Khi biên dịch và chạy đoạn code trên sẽ in ra màn hình `20` (kiểu String).

Cách sử dụng andThen(Function<? super R,? extends V> after)
Đây là một phương thức default được cung cấp sẵn trong interface Function. Chúng ta cùng xem qua đoạn code bên dưới đây để xem cách sử dụng của nó.
Function<Integer, Integer> f1 = (number) -> number * 2;
Function<Integer, String> f2 = (number) -> String.valueOf("Result: " + number);
Function<Integer, String> f = f1.andThen(f2);
System.out.println(f.apply(10));

Từ đoạn code trên, tôi sẽ giải thích cho các bạn hiểu như sau:
- Function f1: sẽ lấy number * 2 -> kết quả trả về = 20 (Kiểu Integer)
- Function f2: sẽ covert một đối số đầu vào có kiểu Integer về một chuỗi tương ứng là "Result" + number.
- Khi chúng ta gọi f1.andThen(f2) ->kết quả trả về của chúng ta là 1 Function gộp bao gồm nhân number với 2 và chuyển nó sang String.
Biên dịch và chạy đoạn code trên kết quả in ra màn hình là `Result: 20`

Cách sử dụng compose(Function<? super V,? extends T> before)
Phương thức này cũng sẽ trả về một Function, nhưng nó thực hiện ngược lại với andThen. Nó sẽ áp dụng before function lên đối số đầu vào rồi mới thực hiện function của chính nó lên kết quả đầu ra.
Function<Integer, Integer> f1 = (number) -> number * 2;
Function<Integer, String> f2 = (number) -> String.valueOf("Result: " + number);
Function<Integer, String> f = f2.compose(f1);
System.out.println(f.apply(10));
Trong đoạn code này, f2.compose(f1) có nghĩa rằng nó sẽ gọi phương thức apply() của f1 trước sau đó mới gọi đến apply() của f2. Kết quả đầu ra cảu chúng ta là một function f. Kết quả in ra màn hình khi biên dịch và chạy đoạn code trên là `Result: 20`.

Cách sử dụng identity()
Function<Integer, Integer> id = Function.identity();
System.out.println(id.apply(10));
Khi biên dịch đoan code này nó sẽ in ra màn hình số `10`

Như vậy đã xong, chúng ta đã nắm bắt được cách sử dụng cơ bản của Function interface rồi. Cái này khá hữu ích trong trường hợp bạn muốn truyền vào đối số cho một phương thức nào đó ở dạng Lambda Expression. Nó sẽ giúp bạn bảo trì code tốt hơn thay vì phải viết đi viết lại nhiều lần. Chúc các bạn học tốt nhé.