Chào tất cả anh chị em CViet, lâu lắm mềnh với quay trở lại và vẫn ăn hại như xưa [IMG]images/smilies/2.gif[/IMG]. Nhân dịp sau một năm làm một "doc-er" một "excel pro" quyết định "ủ mưu" cắp đit quay về nghề coder, người ta có nói không có gì hạnh phúc hơn được làm công việc mà mình yêu thích. Khởi động bằng một bài chia sẻ về những hiểu biết một "new feature" trong Java 8 đó là biểu thức Lambda. Mong anh chị em đọc vào góp ý [IMG]images/smilies/biggrin.png[/IMG]
Java 8 đã được Oracle ra mắt vào ngày 25/3/2014 với rất nhiều cải tiến. Trong đó đáng chú ý là Java đã chính thức hỗ trợ biểu thức Lambda. Nếu bạn nào đã từng làm việc với C# chắc quá hiểu về biểu thức này rồi nhỉ.
Trước khi vào bài chúng ta hãy xem một ví dụ một danh sách các số nguyên như sau
Mã:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
Vậy thì làm thế nào để duyệt và in ra toàn bộ các số nguyên có trong list? Chắc chắn chúng ta sẽ làm thế này
Mã:
for (Integer numer : numbers) { System.out.println(numer);}
Việc làm này là quá quen thuộc và lặp đi lặp lại một cách rất nhàm chán nhiều lần trong quá trình phát triển các ứng dụng Java.
Mô tả vào đời thực nó sẽ giống thế này:
Một ngày cuối tuần đẹp trời bạn quyết định vào bếp phụ vợ nấu ăn và hãy xem xét cuộc đối thoại sau đây
40pxBạn thấy đoạn hội thoại trên thế nào? Còn tôi thấy nó thật thừa thãi, giống như một đoạn code rác vậy.
Đoạn hội thoại trên có thể "fix" lại như sau:
- Vợ: Anh yêu! Lấy dùm em hết đồ ăn trong tủ lạnh ra nhá:
- Chồng: Ok, honey!
Wow một đoạn ... code tuyệt phải không =))
Và Java 8 cũng cung cấp cho bạn một biểu thức tuyệt vời để giải quyết trường hợp như trên.
Hãy xem lại đoạn code bên trên và thử áp biểu thức Lambda coi
Một biểu thức Lambda sẽ có hai phần một phần là tham số phần kia là hành vi cần thực hiện và được cách nhau bởi một dấu ->
Mã:
numbers.forEach(value -> System.out.println(value));
Ở đây cúng ta thấy biến value là một tham số còn System.out.println(value) là một hành vi (in dãy số)
Chúng ta có thể để ý value không cần khai báo kiểu dữ liệu mà bộ biên dịch vẫn có thể hiểu được. Lợi hai chưa?
Hoặc ta cũng có thể dùng toán tử :: để thực hiện việc này
Mã:
numbers.forEach(System.out::println);
OK! nhìn đoạn code đã trở nên "ngon" và chuyên nghiệp hơn hơn rất nhiều phải không?
Trước khi đọc tiếp bạn hay thử download bộ JDK 8 và Netbean IDE 8.0 để chạy thử coi.
Chúng ta hãy tìm hiểu thêm cái gọi là "hành vi" mà tôi đã đề cập bên trên nhé.
Hãy xét một ví dụ sau:
Ta cần một phương thức để thực hiện tính tổng các số nguyên trong một List?
Rất đơn giản là thực hiện một hàm như sau:
Mã:
public int sumAll(List<Integer> numbers) { int total = 0; for (int number : numbers) { total += number; } return total; }
Vậy cần thêm hai hàm để thực hiện cộng các số lẻ và các số chẵn ???
Code thêm hai hàm như sau nữa ???
Mã:
public int sumAllOdd(List<Integer> numbers) { int total = 0; for (int number : numbers) { if (number % 2 != 0) { total += number; } } return total; } public int sumAllEven(List<Integer> numbers) { int total = 0; for (int number : numbers) { if (number % 2 == 0) { total += number; } } return total; }
Ba hàm trên giống hệt nhau khác nhau mỗi biểu thức điều kiện.
He he chắc bạn cũng đang nghĩ giống tôi hãy thử biểu thức Lambda cho vấn đề này xem
Mã:
public static int sumAllLambda(List<Integer> numbers, Predicate<Integer> p) { int total = 0; for (int number : numbers) { if (p.test(number)) { total += number; } } return total; } public static boolean isPrime() { return true; }
Trước khi giải thích hãy thử áp dụng trong hàm main coi
Gọi hàm để tổng tất cả các số trong list
Mã:
sumAllLambda(numbers, n -> true)
ở đây numebers là list các số nguyên
n là tham số, true là hành vi và hành vi này luôn đúng cho nên hàm test của interface Predicate là luôn pass.
Ta có thể thay true bằng các hành vi như kiểm tra số chẵn như sau
Mã:
sumAllLambda(numbers, n -> n % 2 == 0)
hoặc kiểm tra số lẻ
Mã:
sumAllLambda(numbers, n -> n % 2 != 0)
hoặc các số lớn hơn 3
Mã:
sumAllLambda(numbers, n -> n > 3 == 0)
hoặc thậm chí ta cũng có thể viết một hàm kiểm tra số nguyên tố "isPrime" rồi truyền vào hành vi của biểu thức Lambda đều được.
Mã:
sumAllLambda(numbers, n -> isPrime(n))
Ở đây bạn sẽ thắc mắc với mình là interface Predicate là gì? Trong Java 8 chúng ta có những functional interface hỗ trợ cho việc viết biểu thức Lambda
Trước tiên tôi sẽ giới thiệu về Predicate, Consumer.
Predicate thường dùng để xác định và kiểm tra một đối tượng theo một số tiêu chí
Predicate cung cấp cho chúng ta 5 method sau đây (nguồn Java doc)
Mã:
//Returns a predicate which evaluates to true only if this predicate //and the provided predicate both evaluate to true. and(Predicate<? super T> p) //Returns a predicate which negates the result of this predicate. negate() //Returns a predicate which evaluates to true if either //this predicate or the provided predicate evaluates to true or(Predicate<? super T> p) //Returns true if the input object matches some criteria test(T t) //Returns a predicate that evaluates to true if both or neither //of the component predicates evaluate to true xor(Predicate<? super T> p)
Consumer thường được sử dụng để chấp nhận một đối tượng để thực hiện một hành vi nào đấy, consumer cung cấp cho chúng ta 1 method là
Mã:
/** * Performs this operation on the given argument. * * @param t the input argument */ void accept(T t);
Đọc có vẻ khó hiểu phết nhờ, ví dụ cái nhá.
Ta xét một bài toán sau: Viết một chương chính bán vé, nếu trẻ em dưới 6 tuổi sẽ được giảm giá 50%
Ta sẽ khai báo một lớp khách hàng đơn giản như đan rổ như sau:
Mã:
public static class Customer { int age = 0; float price = 0; float discount = 0; public Customer(int age, int price, int discount) { this.age = age; this.price = price; this.discount = discount; } public void printTicketPrice() { float newPrice = price - discount; System.out.println("Ticket price: " + newPrice); } }
Ta viết thêm một method sử lý tính tiền vé như sau
Mã:
public static Customer updateTicketPrice(Customer customer, Predicate<Customer> predicate, Consumer<Customer> consumer) { //Ở đây ta xử dụng method test của Predicate để kiểm tra dữ liệu đầu vào. if (predicate.test(customer)) { //Ở đây ta dùng method accept của Consumer để discount giá vé. consumer.accept(customer); } return customer; }
Ta viết một hàm main rồi áp dụng biểu thức Lambda như sau xem
Mã:
int ticketPrice = 50000; Customer customer1 = new Customer(27, ticketPrice, 0); customer1 = updateTicketPrice(customer1, //Lambda expression for Predicate interface customer -> customer.age <= 6, //Lambda expression for Consumer interface customer -> customer.discount = ticketPrice/2); customer1.printTicketPrice(); Customer customer2 = new Customer(6, ticketPrice, 0); customer2 = updateTicketPrice(customer2, //Lambda expression for Predicate interface customer -> customer.age <= 6, //Lambda expression for Consumer interface customer -> customer.discount = ticketPrice/2); customer2.printTicketPrice(); Chạy thử và in ra màn hình bạn sẽ thấy hai kết quả sau:
Mã:
Ticket price: 50000.0
Ticket price: 25000.0
Vậy ta có thể thấy customer2 là một đứa trẻ 6 tuổi và nó được giảm giá 50%
(Còn tiếp)
View more random threads:
Dưới ánh nắng mặt trời đang lên, những đống pallet nhựa An Giang trải dài mênh mông như những bức tranh tự nhiên đầy sắc màu. Mỗi chiếc pallet nhựa không chỉ là một vật dụng thông thường mà còn là...
Pallet nhựa An Giang giao hàng...