Java Lambda Expression (biểu thức Lambda) là một tính năng được thêm vào Java 8. Đây là một tính năng rất thú vị và nó đã góp phần thay đổi xu hướng lập trình trong Java. Đây là tính năng mà mình nghĩ là các bạn newbie nên dành thời gian để tìm hiểu và nắm bắt. Thú thật sau 1 năm làm việc, mình chẳng hề biết đến Lambda là gì. Cho tới khi mình tham gia dự án Java 8, mình bắt đầu tiếp xúc với biểu thức Lambda và nó đã làm thay đổi hoàn toàn tư duy cũng như phong cách code của mình. Trong bài viết này, mình sẽ tập trung giải thích một cách chi tiết nhất có thể để các bạn newbie có thể làm quen và sử dụng biểu thức Lambda vào code của mình. Những gì mình viết đều dựa trên những gì mình mày mò và rút ra trong quá trình làm việc nên hi vọng sẽ giúp ích cho các bạn. Không dài dòng nữa, mình xin bắt đầu ngay đây.
Trước khi làm quen với Lambda thì chúng ta cần phải nắm rõ một khái niệm rất quan trọng là Functional Interface. Functional Interface là một interface (chắc chắn rồi) chỉ chứa một và chỉ một abtract method. Nên nhớ rõ đặc điểm này: một và chỉ một phương thức abtract. Do đó nó cũng có thể được gọi là Single Abstract Method (SAM – cái tên nói lên tất cả).
Ví dụ về Functional Interface:
interface Hello {
public void sayHello(String helloMessage);
}
Java 8 cũng giới thiệu một annotation mới là @FunctionalInterface để chúng ta đánh dấu interface đó là Functional interface. Việc thêm annotation @FunctionalInterface là không bắt buộc tuy nhiên nó là cần thiết khi khai báo một functional interface. Bởi vì việc thêm @FunctionalInterface sẽ giúp bắt lỗi ở thời điểm biên dịch nếu vô tình thêm một method trừu tượng khác nữa vào interface có đánh dấu bởi annotation này.
Một số quy tắc khai báo Functional Interface
Vì sao chúng ra phải nắm rõ Functional Interface. Nguyên nhân rất đơn giản, một trong các ứng dụng quan trọng nhất của Lambda Expression để tạo ra thể hiện (instance) cho interface đó.
Java 8 giới thiệu một toán tử mới là toán tử mũi tên ->. Toán tử này được dùng trong biểu thức Lambda với mục đích chia biểu thức Lambda thành 2 phần: tham số và nội dung thực thi
Ví dụ:
(int a, int b) -> { do something };
Biểu thức Lambda có thể được định nghĩa là một hàm ẩn danh (anonymous function). Vì là hàm ẩn danh nên nó có đầy đủ đặt điểm của một hàm là có các tham số (parameters) và nội dung thực thi (body). Tham số của một hàm thì có thể có hoặc không, tương tự nội dung thực thi thì có thể có kiểu trả về hoặc không có kiểu trả về. Biểu thức Lambda sẽ dựa trên danh sách tham số đầu vào và xử lý bằng những lệnh ở phần body để cho ra kết quả.
Biểu thức Lambda cung cấp cách thức implement cho method được định nghĩa ở functional interface. Bên cạnh đó biểu thức Lambda cũng cung cấp các thư viện giúp cải tiến cách thức làm việc với Collection như duyệt, filter, và truy xuất dữ liệu…
Với những đặc điểm trên, Lambda giúp giảm số dòng code. Bên cạnh đó, biểu thức Lambda còn có thể hỗ trợ thực hiện tuần tự (Sequential) và song song (Parallel) hiệu quả hơn thông qua Stream API (mình sẽ không tích hợp kiến thức liên quan đến Stream API vào bài này. Phần kiến thức về biểu thức Lambda và Steam API mình sẽ giới thiệu ở các bài viết sau)
(argument-list) -> {body}
Biểu thức Lambda trong java gồm có 3 thành phần sau:
Ví dụ về biểu thức Lambda
Không có tham số:
@FunctionalInterface
interface Hello {
public String sayHello();
}
public class LambdaExpression {
public static void main(String[] args) {
Hello s = () -> {
return "Hello Lambda.";
};
System.out.println(s.sayHello());
}
}
Có 1 tham số:
@FunctionalInterface
interface Hello {
public String sayHello(String name);
}
public class LambdaExpression {
public static void main(String[] args) {
Hello s = name -> "Hello, " + name;
System.out.println(s.sayHello("Lambda"));
}
}
Có nhiều tham số:
@FunctionalInterface
interface Hello {
public String sayHello(String name, String com);
}
public class LambdaExpression {
public static void main(String[] args) {
Hello s = (name, com) -> "Hello, " + name + ". Welcome to " + com;
System.out.println(s.sayHello("newbie", "Lambda"));
}
}
Về khai báo danh sách tham số:
Đúng: (int a, int b, int n) -> { doSomthing(); }
Sai: (int a; int b; int n) -> { doSomthing(); }
Đúng: (int a, int b) -> { doSomthing(); }
Đúng:(int a) -> { doSomthing(); }
Đúng: a -> { doSomthing(); } //best way of single param
Sai: int a, int b -> { doSomthing(); }
(int a, int b) -> { doSomthing(); } hoặc có thể viết là (a, b) -> { doSomthing(); }
Về trình bày nội dung thực thi:
Đúng:Foo foo = parameter -> buildString(parameter);
Đúng:Foo foo = parameter -> {buildString(parameter); return true;}
Foo foo = parameter -> {
String result = "Something " + parameter;
//many lines of code
return result;
};
Sẽ tốt hơn nếu được viết như sau:
Foo foo = parameter -> buildString(parameter);
private String buildString(String parameter) {
String result = "Something " + parameter;
//many lines of code
return result;
}
Ngoài việc được sử dụng để implement Function interface như ở các ví dụ trên thì biểu thức Lambda còn được sử dụng thường xuyên khi làm việc với Collection. Phổ biến nhất là việc áp dụng biểu thức Lambda vào vòng lặp forEach
List<String> list=new ArrayList<String>();
//init list
list.forEach( n -> System.out.println(n) );
Biểu thức Lambda cũng được dùng để thay thế các Anonymous inner class. Anonymous inner class: Inner class là class (non static) được viết trong một class khác (out-class). Anonymous class là Inner class nhưng không có ''class' đặt trước tên của class. Khi thực hiện sắp xếp với Collection, chắc hẳn mọi nguời đều tiếp xúc với một Anonymous inner class là Comparator rồi nhỉ.
Trường hợp dùng Comparator
listDevs.sort(new Comparator<Developer>() {
@Override
public int compare(Developer o1, Developer o2) {
return o2.getAge() - o1.getAge();
}
});
Trường hợp dùng Lambda
listDevs.sort((Developer o1, Developer o2)->o1.getAge()-o2.getAge());
Biểu thức Lambda được sử dụng tốt nhất khi kết hợp với Function interface. Bạn không thể sử dụng biểu thức Lambda với một interface có nhiều hơn một abtract method. Các lưu ý khi khởi tạo một Function interface:
Vì biểu thức Lambda là tính năng trong Java 8 nên hãy chắc chắn rằng bạn đã cài đặt Java 8 hoặc mới hơn. Biểu thức Lambda không khả dụng cho Java 7 hoặc các phiên bản sớm hơn.
Biểu thức Lambda cũng được dùng để thay thế các Anonymous inner class. Tuy nhiên, hãy tìm hiểu kỹ về sự khác biệt giữa chúng để có thể sử dụng biểu thức Lambda một cách thích hợp.
Unpublished comment
Viết câu trả lời