Lambda Expressions là một trong những tính năng mới được giới thiệu trong Java 8. Nó tạo điều kiện cho các lập trình viên lập trình Functional và phát triển ứng dụng đơn giản hơn rất nhiều so với những phiên bản trước đó.
Java 8 - Tìm hiểu về Lambda Expressions

Ví dụ đơn giản nhất mà bạn có thể hình dung và bắt đầu đó là Anonymous Class được viết như sau:
new ImplementInterface {
  @Override
  public returnType defineMethod(args) {
   body code
  }
 }
Thì trong Java 8, chúng ta có thể viết nó ngắn gọn hơn với syntax của Lambda expression như thế này
(args) -> { body code }
Trước đây, khi bạn lập trình ứng dụng với Swing trong Java, nếu như bạn muốn thêm một ActionListener cho button thì trong code chúng ta phải implement kiểu như thế này
button.addActionListener(new ActionListener() {
  @Override
  public void actionPerformed(ActionEvent e) {
   // Code thực thi viết ở đây.
  }
 });
Nhưng trong Java 8, bạn có thể sử dụng Lambda Expression để làm cho nó trở nên ngắn gọn hơn rất nhiều.
button.addActionListener(e -> {
  // Code thực thi viết ở đây
});
So sánh 2 cách viết chắc hẳn rằng bạn sẽ thấy cách thứ 2 ngắn gọn hơn và rõ ràng hơn rất nhiều có đúng không nào.

Trong Java 8, Lambda Expressions được sử dụng chủ yếu để định nghĩa nội tuyến một Functional Interface. Mà ở đây, Functional interface thực ra nó là một interface chỉ chứa 1 phương thức abstract duy nhất và được khai báo với annotation @FunctionalInterface. Trong ví dụ trên bạn cũng đã thấy, thay vì chúng ta định nghĩa lại ActionListener interface để thực thi những dòng code bên trong cho phương thức actionPerformed() thì chúng ta có thể dùng Lambda Expression để thực thi.

Một ví dụ khác mà chúng ta có thể tham khảo đó chính là Runnable interface. Trước đây, khi chúng ta muốn tạo Thread để xử lý đa luồng phải tạo ra một lớp mới và cho nó implements Runnable, sau đó phải Override phương thức run(). Một cách khác mà chúng ta vẫn thường dùng là viết thẳng trong đoạn code của mình như ví dụ bên dưới.
package com.vanthuong.tutorial;

public class Application {

  public static void main (String... args) {
    Runnable runnable = new Runnable() {
      @Override
      public void run() {
        // Đoạn code thực thi
      }
    };
    
    new Thread(runnable).start()
  }
}
Nếu yêu cầu phải sử dụng Java 7 thì chúng ta sẽ phải chấp nhận với cách viết như trên. Nhưng khi chuyển sang Java 8, mọi thứ được viết lại đơn giản hơn rất nhiều. Bắt đầu từ việc implement code cho runnable, mọi thứ trở nên ngắn gọn hơn.
Runnable runnable = () -> {
  // Đoạn code thực thi
}
Sau khi đã có runnable thì chúng ta có thể tạo Thread và thực thi thôi
new Thread(runnable).start();
Bạn hoàn toàn có thể implement runnable trực tiếp khi gọi Constructor của Thread kiểu như vầy
new Thread(()->{
  // Đoạn code thực thi
}).start()

Chúng ta đã đi qua 2 ví dụ và mình nghĩ rằng bạn đã có thể biết được cách mà Lambda Expression làm việc trong Java 8 như thế nào rồi phải không. Tuy nhiên, chúng ta còn một số thứ hay ho khác để vọc nữa. Bạn có thể viết lambda expression bằng nhiều cách tùy thuộc vào việc sử dụng nó trong một số trường hợp như sau.
  • Tùy chọn khai báo kiểu dữ liệu: Bạn không cần phải khai báo kiểu dữ liệu cho các parameter truyền vào. Trình biên dịch sẽ tự suy luận ra kiểu dữ liệu từ giá trị của các parameter
  • Tùy chọn sử dụng dấu ngoặc: Trong trường hợp bạn chỉ truyền vào một parameter duy nhất thì chúng ta có thể bỏ qua. Nếu như có nhiều parameter thì phải sử dụng dấu ngoặc nhé
  • Tùy chọn sử dụng dấu ngoặc nhọn: Trong trường hợp phần body code của chúng ta chỉ thực hiện 1 statement duy nhất thì chúng ta cũng có thể loại bỏ luôn 2 dấu ngoặc nhọn {} để làm cho nó trở nên ngắn hơn nữa
  • Tùy chọn sử dụng lệnh return: Trình biên dịch sẽ tự động return về giá trị nếu như phần body code của chúng ta chỉ thực hiện một biểu thức có trả về giá trị. Trong trường hợp này, dấu ngoặc nhọn yêu cầu bắt buộc phải sử dụng nhé

Dưới đây là ví dụ minh họa cho 4 concepts mà mình vừa mới đề cập ở trên.
public class LambdaExpression {

    public static void main(String[] args) {
        LambdaExpression tester = new LambdaExpression();

        // Có khai báo kiểu dữ liệu cho các parameter
        MathOperation addition = (int a, int b) -> a + b;

        // Tùy chọn khai báo kiểu dữ liệu
        MathOperation subtraction = (a, b) -> a - b;

        // Câu lệnh return yêu cầu phải có các dấu {}
        MathOperation multiplication = (int a, int b) -> {
            return a * b;
        };

        // Note 1: Tùy chọn sử dụng lệnh "return" nếu chỉ thực hiện 1 statement
        // duy nhất Compiler sẽ tự trả về kết quả của biểu thức a/b

        // Note 2: Tùy chọn sử dụng {} nếu chỉ thực hiện 1 statement duy nhất
        MathOperation division = (int a, int b) -> a / b;

        // In kết quả ra màn hình
        System.out.println("10 + 5 = " + tester.operate(10, 5, addition));
        System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction));
        System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication));
        System.out.println("10 / 5 = " + tester.operate(10, 5, division));

        // Tùy chọn không sử dụng dấu ngoặc khi chỉ có 1 parameter
        GreetingService greetingService1 = message -> System.out.println("Hello " + message);

        // Tùy chọn sử dụng dấu ngoặc cho parameter
        GreetingService greetingService2 = (message) -> System.out.println("Hello " + message);

        greetingService1.printMessage("Alice");
        greetingService2.printMessage("Max");

    }

    private int operate(int a, int b, MathOperation mathOperation) {
        return mathOperation.operation(a, b);
    }

    // Khai báo các inner interface
    interface MathOperation {
        int operation(int a, int b);
    }

    interface GreetingService {
        void printMessage(String message);
    }
}
Các bạn có thể biên dịch và chạy chương trình để xem kết quả nhé. Nó sẽ in ra màn hình như sau:
10 + 5 = 15
10 - 5 = 5
10 x 5 = 50
10 / 5 = 2
Hello Alice
Hello Max