# Java - Lambda Expressions

Xin chào các pháp sư Java tương lai! Hôm nay, chúng ta sẽ bắt đầu một hành trình đầy.exciting vào thế giới của Lambda Expressions. Đừng lo lắng nếu bạn là người mới bắt đầu lập trình - tôi sẽ hướng dẫn bạn từng bước qua khái niệm này, genau như tôi đã làm cho hàng trăm sinh viên trong những năm dạy học của mình. Vậy, hãy lấy một tách cà phê (hoặc trà, nếu đó là sở thích của bạn), và chúng ta cùng nhảy vào!

## Lambda Expressions là gì?

Hãy tưởng tượng bạn đang ở một buổi tiệc và bạn muốn kể một câu chuyện cười cho bạn bè. Thay vì viết cả câu chuyện và truyền纸 around, có phải sẽ dễ dàng hơn nếu bạn chỉ cần nói ra? Đó chính xác là điều Lambda Expressions làm trong Java - chúng cung cấp một cách nhanh chóng và ngắn gọn để biểu đạt các thể hiện của các interface có một phương thức (functional interfaces).

Lambda Expressions được giới thiệu trong Java 8 để mang lại một số lợi ích của lập trình hàm vào Java. Chúng làm cho mã của bạn dễ đọc hơn, ngắn gọn hơn và đôi khi hiệu quả hơn.

### Cú pháp Lambda Expression

Cú pháp cơ bản của một Lambda Expression trông như thế này:

```java
(parameters) -> { body }

Nó giống như một hàm nhỏ không có tên. Hãy phân tích nó:

Java - Lambda Expressions

  • parameters: Đây là các tham số đầu vào (nếu có)
  • ->: This arrow token is used to separate the parameters from the body
  • body: Đây chứa mã cần thực thi

Đặc điểm của Lambda Expression trong Java

  1. Type inference: Java thường có thể suy ra loại của các tham số, vì vậy bạn không always cần phải chỉ định chúng.
  2. Single expression: Nếu thân chứa chỉ một biểu thức, bạn có thể bỏ qua các dấu ngoặc {}
  3. Multiple parameters: Bạn có thể có không, một hoặc nhiều tham số.
  4. Return statement: Nếu thân có một biểu thức duy nhất, câu lệnh return là tùy chọn.

Ví dụ về Lambda Expression trong Java

Hãy cùng xem một số ví dụ để thấy Lambda Expressions hoạt động như thế nào trong thực tế.

Ví dụ 1: Lambda Expression đơn giản

// Cách truyền thống
Runnable runnable = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello, World!");
    }
};

// Cách Lambda
Runnable lambdaRunnable = () -> System.out.println("Hello, Lambda World!");

// Chạy cả hai
runnable.run();
lambdaRunnable.run();

Trong ví dụ này, chúng ta đang tạo một đối tượng Runnable. Cách truyền thống yêu cầu chúng ta tạo một lớp inner匿名, trong khi cách Lambda ngắn gọn hơn nhiều. Cả hai đều sẽ in ra một thông báo khi chạy.

Ví dụ 2: Lambda với tham số

interface MathOperation {
    int operate(int a, int b);
}

public class LambdaExample {
    public static void main(String[] args) {
        MathOperation addition = (a, b) -> a + b;
        MathOperation subtraction = (a, b) -> a - b;

        System.out.println("10 + 5 = " + addition.operate(10, 5));
        System.out.println("10 - 5 = " + subtraction.operate(10, 5));
    }
}

Ở đây, chúng ta định nghĩa một interface hàm MathOperation và sử dụng Lambda Expressions để thực hiện các phép toán cộng và trừ. Chú ý xem mã trở nên干净 và dễ đọc như thế nào!

Phạm vi của Lambda Expression trong Java

Lambda Expressions có cùng phạm vi như các lớp inner. Chúng có thể bắt giữ các biến từ phạm vi bao quanh, nhưng các biến này phải là effectively final (giá trị của chúng không thay đổi sau khi khởi tạo).

public class ScopeExample {
    public static void main(String[] args) {
        int multiplier = 2;
        IntUnaryOperator doubler = (n) -> n * multiplier;
        System.out.println(doubler.applyAsInt(4)); // Outputs: 8

        // Điều này sẽ gây ra lỗi:
        // multiplier = 3;
    }
}

Trong ví dụ này, multiplier là effectively final và có thể được sử dụng trong Lambda Expression.

Sử dụng Constants trong Lambda Expression

Các hằng số có thể được sử dụng tự do trong Lambda Expressions. Chúng là một cách tuyệt vời để làm cho Lambda Expressions của bạn linh hoạt và tái sử dụng hơn.

public class ConstantExample {
    private static final int MAGIC_NUMBER = 42;

    public static void main(String[] args) {
        IntSupplier magicSupplier = () -> MAGIC_NUMBER;
        System.out.println("The magic number is: " + magicSupplier.getAsInt());
    }
}

Ở đây, chúng ta sử dụng một hằng số MAGIC_NUMBER trong Lambda Expression của mình. Điều này hoàn toàn ổn và không vi phạm bất kỳ quy tắc phạm vi nào.

Sử dụng Lambda Expression trong Collections

Lambda Expressions thực sự tỏa sáng khi làm việc với các bộ sưu tập. Chúng có thể làm cho mã của bạn dễ đọc và ngắn gọn hơn. Hãy xem một vài ví dụ:

Sắp xếp một List

List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");

// Cách truyền thống
Collections.sort(names, new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return b.compareTo(a);
    }
});

// Cách Lambda
names.sort((a, b) -> b.compareTo(a));

System.out.println(names); // Outputs: [David, Charlie, Bob, Alice]

Lặp qua một List

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// Cách truyền thống
for (Integer number : numbers) {
    System.out.println(number);
}

// Cách Lambda
numbers.forEach(number -> System.out.println(number));

// Hoặc thậm chí ngắn gọn hơn
numbers.forEach(System.out::println);

Lọc một List

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

// Lấy các số chẵn
List<Integer> evenNumbers = numbers.stream()
                                   .filter(n -> n % 2 == 0)
                                   .collect(Collectors.toList());

System.out.println(evenNumbers); // Outputs: [2, 4, 6, 8, 10]

Trong ví dụ cuối cùng này, chúng ta sử dụng API Stream cùng với Lambda Expression để lọc các số chẵn từ danh sách của mình. Phương thức filter nhận một Predicate ( một hàm trả về boolean), mà chúng ta cung cấp bằng cách sử dụng Lambda Expression.

Kết luận

Và thế là bạn đã có, các bạn! Chúng ta đã cùng nhau hành trình qua vùng đất của Lambda Expressions, từ cú pháp cơ bản đến các ứng dụng thực tế trong bộ sưu tập. Nhớ rằng, Lambda Expressions giống như gia vị trong nấu ăn - sử dụng chúng một cách khôn ngoan, và chúng có thể làm cho mã của bạn trở nên thú vị hơn (và ở đây, thú vị có nghĩa là dễ đọc và hiệu quả hơn!).

Như với bất kỳ khái niệm mới nào, chìa khóa để thành thạo Lambda Expressions là thực hành. Vậy, hãy đi và lambda-fy mã của bạn! và nhớ rằng, ngay cả khi bạn gặp lỗi trên đường đi, đó đều là cơ hội để phát triển. Như tôi luôn nói với sinh viên của mình, trong lập trình, lỗi là những cơ hội phát triển ẩn sau.

Tiếp tục lập trình, tiếp tục học hỏi, và quan trọng nhất, hãy vui vẻ với nó! Đến gặp lại các bạn, này là giáo viên Java hàng xóm thân thiện của bạn đang tạm biệt. Chúc các bạn lập trình vui vẻ!

Credits: Image by storyset