Java - giao diện chức năng

Xin chào, những nhà phát triển Java tương lai! Hôm nay, chúng ta sẽ bắt đầu hành trình hấp dẫn vào thế giới các giao diện chức năng trong Java. Đừng lo nếu bạn mới bắt đầu học lập trình; tôi sẽ hướng dẫn bạn qua khái niệm này bước bước, như cách tôi đã làm cho nhiều học viên khác trong những năm dạy học. Vậy, hãy lấy ly cà phê (hoặc đồ uống yêu thích của bạn), và hãy bắt đầu!

Java - Functional Interfaces

Giao diện chức năng là gì?

Hãy tưởng tượng bạn đang ở tiệc, và bạn được gán vai trò của một DJ. Công việc của bạn rất đơn giản: phát nhạc. Bạn không cần lo về việc phục vụ thức ăn hoặc trang trí sân khấu. Trong Java, một giao diện chức năng tương tự như DJ đó - nó có một công việc cụ thể để làm và làm nó một cách tốt.

Trong các thuật ngữ kỹ thuật, giao diện chức năng là một giao diện chứa đúng một phương thức trừu tượng. Nó có thể có các phương thức khác, nhưng chúng phải là các phương thức mặc định hoặc tĩnh. Phương thức trừu tượng duy nhất là điều khiến giao diện chức năng có tính "chức năng".

Ví dụ 1: Một giao diện chức năng đơn giản

@FunctionalInterface
interface Greeter {
void greet(String name);
}

Trong ví dụ này, Greeter là một giao diện chức năng. Nó chỉ có một phương thức trừu tượng greet, đối với một tham số kiểu chuỗi và không trả về gì (void).

Phụ lục @FunctionalInterface

Bạn có thể nhận ra phụ lục @FunctionalInterface trong ví dụ của chúng ta. Đó giống như đặt một huy hiệu "DJ" trên giao diện của chúng ta. Nó nói với Java, "Ôi, giao diện này có ý là chức năng!" Nếu chúng ta nhầm thêm một phương thức trừu tượng khác, Java sẽ đưa ra lỗi, giúp chúng ta duy trì tính chức năng của giao diện.

Sử dụng giao diện chức năng

Bây giờ khi chúng ta biết giao diện chức năng là gì, hãy xem cách chúng ta có thể sử dụng chúng. Một trong những điều tuyệt vời nhất về giao diện chức năng là chúng ta có thể sử dụng chúng với các biểu thức lambda, là những cách viết ngắn gọn hơn của các phương thức.

Ví dụ 2: Sử dụng giao diện chức năng với biểu thức lambda

public class GreeterTest {
public static void main(String[] args) {
Greeter friendlyGreeter = (name) -> System.out.println("Xin chào, " + name + "! Bạn thế nào?");
friendlyGreeter.greet("Alice");

Greeter formalGreeter = (name) -> System.out.println("Chào buổi sáng, " + name + ". Tôi hy vọng bạn khỏe.");
formalGreeter.greet("Ông Smith");
}
}

Trong ví dụ này, chúng ta đang tạo hai greeter khác nhau sử dụng giao diện Greeter của chúng ta. Các biểu thức lambda (name) -> ... đang triển khai phương thức greet một cách nhanh chóng. Đó như thuê hai DJ khác nhau cho hai tiệc khác nhau!

Khi bạn chạy mã này, bạn sẽ thấy:

Xin chào, Alice! Bạn thế nào?
Chào buổi sáng, Ông Smith. Tôi hy vọng bạn khỏe.

Các loại giao diện chức năng trong Java

Java cung cấp một số giao diện chức năng tích hợp để làm cho cuộc sống của chúng ta dễ dàng hơn. Hãy xem một số loại thường được sử dụng nhất:

1. Predicate

Giao diện Predicate<T> được sử dụng cho các hàm có giá trị boolean với một tham số. Nó giống như một câu hỏi có thể trả lời với có hoặc không.

import java.util.function.Predicate;

public class PredicateExample {
public static void main(String[] args) {
Predicate<Integer> isAdult = age -> age >= 18;

System.out.println("20 có phải là tuổi người lớn? " + isAdult.test(20));
System.out.println("15 có phải là tuổi người lớn? " + isAdult.test(15));
}
}

Điều này sẽ đầu ra:

20 có phải là tuổi người lớn? true
15 có phải là tuổi người lớn? false

2. Function<T,R>

Giao diện Function<T,R> đại diện cho một hàm chấp nhận một tham số và sản xuất một kết quả. Nó giống như một máy móc nhận vào điều gì đó và trả ra điều gì đó khác.

import java.util.function.Function;

public class FunctionExample {
public static void main(String[] args) {
Function<String, Integer> stringLength = str -> str.length();

System.out.println("Độ dài của 'Xin chào': " + stringLength.apply("Xin chào"));
System.out.println("Độ dài của 'Java rất thú vị': " + stringLength.apply("Java rất thú vị"));
}
}

Điều này sẽ đầu ra:

Độ dài của 'Xin chào': 9
Độ dài của 'Java rất thú vị': 16

3. Consumer

Giao diện Consumer<T> đại diện cho một hoạt động chấp nhận một tham số đầu vào và không trả về kết quả. Nó giống như một hố đen cửa nhân chất hấp dẫn dữ liệu nhưng không sản xuất điều gì.

import java.util.function.Consumer;

public class ConsumerExample {
public static void main(String[] args) {
Consumer<String> printer = message -> System.out.println("In: " + message);

printer.accept("Xin chào, giao diện chức năng!");
printer.accept("Java rất thú vị!");
}
}

Điều này sẽ đầu ra:

In: Xin chào, giao diện chức năng!
In: Java rất thú vị!

4. Supplier

Giao diện Supplier<T> đại diện cho một nhà cung cấp kết quả. Nó không chấp nhận tham số nhưng sản xuất một giá trị. Nó giống như một máy bán hàng tự động cung cấp bạn điều gì đó mà không cần bạn đưa điều gì vào.

import java.util.function.Supplier;
import java.util.Random;

public class SupplierExample {
public static void main(String[] args) {
Supplier<Integer> randomNumberSupplier = () -> new Random().nextInt(100);

System.out.println("Số ngẫu nhiên: " + randomNumberSupplier.get());
System.out.println("Số ngẫu nhiên khác: " + randomNumberSupplier.get());
}
}

Điều này sẽ đầu ra hai số ngẫu nhiên từ 0 đến 99, ví dụ:

Số ngẫu nhiên: 42
Số ngẫu nhiên khác: 73

Các giao diện chức năng tồn tại trước Java 8

Trước khi Java 8 giới thiệu khái niệm giao diện chức năng, Java đã có một số giao diện phù hợp với định nghĩa. Các giao diện này chủ yếu được sử dụng trong việc xử lý sự kiện và lập trình đồng bộ. Hãy xem một số ví dụ:

1. Runnable

Giao diện Runnable đã tồn tại từ những ngày đầu tiên của Java. Nó thường được sử dụng để tạo các luồng.

public class RunnableExample {
public static void main(String[] args) {
Runnable helloRunnable = () -> System.out.println("Xin chào từ một luồng!");
new Thread(helloRunnable).start();
}
}

Điều này sẽ đầu ra:

Xin chào từ một luồng!

2. Comparator

Giao diện Comparator được sử dụng để định nghĩa thứ tự tùy chỉnh cho các đối tượng.

import java.util.Arrays;
import java.util.Comparator;

public class ComparatorExample {
public static void main(String[] args) {
String[] names = {"Alice", "Bob", "Charlie", "David"};

Comparator<String> lengthComparator = (s1, s2) -> s1.length() - s2.length();

Arrays.sort(names, lengthComparator);

System.out.println("Sắp xếp theo độ dài: " + Arrays.toString(names));
}
}

Điều này sẽ đầu ra:

Sắp xếp theo độ dài: [Bob, Alice, David, Charlie]

Kết luận

Xin chúc mừng! Bạn đã bước ra đầu tiên vào thế giới các giao diện chức năng trong Java. Chúng ta đã bàn về chúng là gì, cách sử dụng chúng và một số loại phổ biến. Hãy nhớ rằng các giao diện chức năng như là các công cụ đặc biệt trong hộp công cụ Java của bạn. Chúng giúp bạn viết mã sạch hơn, trình bày tốt hơn.

Khi bạn tiếp tục hành trình với Java, bạn sẽ tìm thấy nhiều ứng dụng hơn nữa cho các giao diện chức năng. Chúng rất mạnh mẽ khi làm việc với các luồng và tập hợp, điều chúng ta sẽ bàn trong các bài học tương lai.

Hãy tiếp tục tập luyện, giữ được sự tò mò và quan trọng nhất, hãy vui vẻ khi lập trình! Java là một ngôn ngữ rộng lớn và thú vị, và bạn đang ở đúng hướng để nắm vững nó. Đến lần sau, chúc bạn có một ngày lập trình vui vẻ!

Credits: Image by storyset