1. Functional Interface là gì?
Functional Interface là interface có duy nhất 1 method trừu tượng (có thể có thêm các method không trừu tượng bằng từ khóa default trong Java 8)
Ví dụ: Comparable
là 1 Functional Interface với method trừu tượng duy nhất compareTo
; Runnable
là 1 Functional Interface với method trừu tượng duy nhất run
…
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
Việc dùng annotation @FunctionalInterface là không bắt buộc nhưng nó giúp đảm bảo cho quá trình compile. Ví dụ bạn khai báo @FunctionalInterface nhưng trong interface lại có nhiều hơn 2 method trừu tượng thì nó sẽ báo lỗi.
2. Functional Interface API trong Java 8
Java 8 xây dựng sẵn một số functional interface và nó được dùng nhiều trong các biểu thức lambda:
2.1. java.util.function.Consumer
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Consumer<T> {
// Phương thức chấp nhận một tham số đầu vào
// và không trả về gì cả.
void accept(T t);
}
consumer thường được dùng với list, stream để xử lý với các phần tử bên trong.
Ví dụ: đoạn code dưới đây in ra tất cả các giá trị của 1 list
List<String> list = Arrays.asList("stack", "java", "stackjava.com");
// Sử dụng List.forEach(Consumer) để in ra giá trị của các phần tử trong list
list.forEach(new Consumer<String>() {
@Override
public void accept(String t) {
System.out.println(t);
}
});
System.out.println("----------------");
// Sử dụng List.forEach(Consumer) với cú pháp lambda expression:
list.forEach(t -> System.out.println(t));
Kết quả:
stack
java
stackjava.com
----------------
stack
java
stackjava.com
2.2. java.util.function.Predicate
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Predicate<T> {
// Kiểm tra một tham số đầu vào và trả về true hoặc false.
boolean test(T t);
}
predicate thường được dùng với list, stream để kiểm tra từng phần tử lúc xóa, lọc…
Ví dụ: đoạn code dưới đây xóa bỏ tất cả các số âm khỏi 1 ArrayList<Integer>
List<Integer> list = new ArrayList<>();
list.add(-1);
list.add(1);
list.add(0);
list.add(-2);
list.add(3);
// lệnh removeIf sẽ thực hiện duyệt từng phần tử,
// nếu method test của Predicate trả về true thì sẽ remove phần tử đó khỏi list
list.removeIf(new Predicate<Integer>() {
@Override
public boolean test(Integer t) {
return t < 0;
}
});
list.forEach(t -> System.out.println(t));
System.out.println("-----------------------------");
// Sử dụng Predicate với cú pháp Lambda Expression
// loại bỏ các phần tử lớn hơn 1
list.removeIf(t -> t > 1);
list.forEach(t -> System.out.println(t));
Kết quả:
1
0
3
-----------------------------
1
0
2.3. java.util.function.Function
package java.util.function;
import java.util.Objects;
@FunctionalInterface
public interface Function<T, R> {
// Method này nhận đầu vào là 1 tham số và trả về một giá trị.
R apply(T t);
}
Function thường dùng với Stream khi muốn thay đổi giá trị cho từng phần tử trong stream.
Ví dụ: đoạn code dưới đây thực hiện chuyển các phần phần tử kiểu string trong 1 stream thành chữ in hoa/thường:
List<String> list = Arrays.asList("stack", "JAVA", "demo", "Function");
Stream<String> stream = list.stream();
// chuyển tất cả các phần tử của stream thành chữ in hoa
stream.map(new Function<String, String>() {
@Override
public String apply(String t) {
return t.toUpperCase();
}
}).forEach(t -> System.out.println(t));
System.out.println("---------------");
// Function với cú pháp Lambda Expression
// chuyển tất cả các phần tử của stream thành chữ thường
stream = list.stream();// lưu ý là stream ko thể dùng lại nên phải khởi tạo lại
stream.map(t -> t.toLowerCase()).forEach(t -> System.out.println(t));
Kết quả:
STACK
JAVA
DEMO
FUNCTION
---------------
stack
java
demo
function
Một số Function interface tương tự:
- java.util.function.IntFunction: dữ liệu chuyển về kiểu Integer
- java.util.function.DoubleFunction: dữ liệu chuyển về kiểu Double
- java.util.function.LongFunction: dữ liệu chuyển về kiểu Long
2.4. java.util.function.Supplier
package java.util.function;
@FunctionalInterface
public interface Supplier<T> {
// method này không có tham số nhưng trả về một kết quả.
T get();
}
Ví dụ: đoạn code dưới đây tạo ra 1 list gồm 10 số 1 cách random:
Random random = new Random();
Stream<Integer> stream = Stream.generate(new Supplier<Integer>() {
@Override
public Integer get() {
return random.nextInt(10);
}
}).limit(5);
stream.forEach(t -> System.out.print(t +" "));
System.out.println("\n--------------------");
// Sử dụng Supplier với cú pháp Lambda Expression:
stream = Stream.generate(() -> random.nextInt(10)).limit(5);
stream.forEach(t -> System.out.print(t +" "));
Kết quả:
4 9 8 5 8
--------------------
2 2 9 9 6
References:
https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html
Cám ơn bạn đã theo dõi!!!
Bình luận