Bài viết được sự cho phép của tác giả Trần Hữu Cương
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ấtcompareTo; Runnable là 1 Functional Interface với method trừu tượng duy nhất run…
Về annotation @FunctionalInterface: nó được dùng ở trước mỗi interface để khai báo đây là 1 functional interface.
@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
Xem thêm nhiều việc làm Java lương cao trên TopDev
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<R>: dữ liệu chuyển về kiểu Integer
- java.util.function.DoubleFunction<R>: dữ liệu chuyển về kiểu Double
- java.util.function.LongFunction<R>: 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
Bài viết gốc được đăng tải tại stackjava.com
Có thể bạn quan tâm:
- Cách xây dựng ThreadLocal trong Java
- Top 10 câu hỏi phỏng vấn Java Developer thường gặp
- Hướng dẫn Java Design Pattern – Flyweight
Tuyển dụng IT lương cao, đãi ngộ hấp dẫn. Ứng tuyển ngay!