Tong Hoang Vu
Tong Hoang Vu's blog

Tong Hoang Vu's blog

Sử dụng lazy evaluation với lambda expression

Sử dụng lazy evaluation với lambda expression

Java Stream API

Tong Hoang Vu's photo
Tong Hoang Vu
·Sep 6, 2021·

3 min read

Subscribe to my newsletter and never miss my upcoming articles

Đúng ra mình phải bắt đầu giới thiệu vô Stream API, cơ mà mình mới phát hiện ra cái này khá hay nên đưa vô bài luôn. Mọi người thông cảm nhé 😂 Đây là kĩ thuật khá hay và phổ biến (web, framework,... cũng có). Đó chính là lazy, hiểu đơn giản là chỉ load khi sử dụng tới.

Tuy cái này không giúp tăng tốc độ nhiều, nhưng trong vài ngữ cảnh nó sẽ rất rất hữu ích. Ví dụ đơn giản như logging trong hệ thống lớn, hàm logging có thể chạy rất nhiều lần, cho nên việc tối ưu xíu xiu như thế này sẽ giúp tăng tốc khá nhiều trong trường hợp đấy.

1. Eager evaluation

Ở đây xét trong ngữ cảnh gọi method trong Java. Ví dụ mình có 2 method như sau.

public String getMessage() {
    System.out.println("Retrieving message...");
    return "Hello world";
}

// Thường thì có log level, mà ở đây dùng boolean cho dễ
public void log(boolean enabled, String message) {
    if (enabled)
        System.out.println(message);
}
...
log(false, getMessage());
log(true, getMessage());

Kết quả sẽ cho ra như sau. Hàm getMessage() luôn được gọi cả khi không cần dùng đến (chỉ cần getMessage() khi mà enabled là true).

Retrieving message...
Retrieving message...
Hello world

Theo mặc định, các đối số truyền vào method là eager evaluation, nghĩa là được tính toán trước rồi mới đưa kết quả vào method.

Như vậy, tưởng tượng trong hệ thống backend, hàm log() như trên được gọi hàng ngàn lần thì sẽ không tốt. Do đó, người ta mới sinh ra các kĩ thuật tối ưu như lazy để dùng trong những trường hợp nhạy cảm đó.

Có thể xem thêm ở đây nhé Logging không hề đơn giản.

2. Lazy evaluation với lambda

Trong tình huống trên nên sử dụng lazy, hàm getMessage() chỉ nên được tính toán khi cần thiết. Trong Java đạt được kĩ thuật này nhờ tính lazy của lambda.

Code sẽ sửa lại như sau.

public String getMessage() {
    System.out.println("Retrieving message...");
    return "Hello world";
}

public void log(boolean enabled, Supplier<String> message) {
    if (enabled)
        System.out.println(message.get());
}
...
log(false, () -> getMessage());
log(true, () -> getMessage());

Và tèn ten, đây là kết quả đạt được. Hàm getMessage() chỉ được gọi duy nhất một lần, ngay khi cần thiết.

Retrieving message...
Hello world

Vì theo mặc định, lambda sẽ không được thực hiện cho tới khi gọi method bên trong của nó. Đây là cách tận dụng đặc điểm của lambda để đạt được lazy evaluation.


Bên cạnh lazy evaluation, còn có một số cách áp dụng khác của lambda nữa. Các bạn có thể tìm hiểu thêm nhé. Bye bye và mãi yêu!

 
Share this