Functional Interface là gì? Functional Interface API trong Java 8

Functional Interface là gì? Functional Interface API trong Java 8

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

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

 

References:

https://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html

stackjava.com