Trong quá trình phát triển phần mềm, việc đóng luồng I/O trong khối finally đã trở thành thói quen và chuẩn mực lập trình. Tuy nhiên, cấu trúc try-with-resources thường là lựa chọn tốt hơn so với try-finally vì những lý do sau đây.
1. Quản lý tài nguyên tự động
try-with-resources được thiết kế dành riêng cho các tài nguyên triển khai giao diện AutoCloseable, như file, kết nối cơ sở dữ liệu, socket mạng, v.v. Khi khối lệnh kết thúc—dù chạy bình thường hay gặp ngoại lệ—tài nguyên sẽ tự động được đóng. Điều này giúp giảm đáng kể lỗi phát sinh trong quản lý tài nguyên.
2. Mã nguồn ngắn gọn hơn
Sử dụng try-with-resources giúp loại bỏ mã mẫu (boilerplate code) không cần thiết. Bạn không phải gọi phương thức close() trong khối finally. Ngược lại, try-finally yêu cầu viết thủ công các lệnh đóng tài nguyên, dễ dẫn đến thiếu sót hoặc trùng lặp.
3. Xử lý ngoại lệ an toàn hơn
Trong cấu trúc try-finally, nếu cả khối try lẫn phương thức close() trong finally đều ném ngoại lệ, ngoại lệ từ finally sẽ che lấp ngoại lệ gốc. Với try-with-resources, ngoại lệ từ việc đóng tài nguyên được gắn thêm dưới dạng Suppressed Exception vào ngoại lệ chính, giúp cung cấp thông tin lỗi đầy đủ và chính xác hơn.
4. Ngăn ngừa rò rỉ tài nguyên
Cơ chế tự động đóng của try-with-resources hiệu quả hơn trong việc phòng tránh rò rỉ tài nguyên. Khi code phức tạp, nếu bạn quên đóng tài nguyên hoặc gặp ngoại lệ khi đóng, try-finally dễ gây ra rò rỉ. try-with-resources đảm bảo tài nguyên luôn được giải phóng đúng cách.
5. Ví dụ mã nguồn
Dưới đây là ví dụ minh họa sự khác biệt giữa try-finally và try-with-resources khi đọc nội dung file và đóng tài nguyên sau khi hoàn thành.
Ví dụ với try-finally:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class TryFinallyDemo {
public static void main(String[] args) {
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new FileReader("data.txt"));
String content;
while ((content = bufferedReader.readLine()) != null) {
System.out.println(content);
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
}
Ví dụ với try-with-resources:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class TryWithResourcesDemo {
public static void main(String[] args) {
try (BufferedReader bufferedReader = new BufferedReader(new FileReader("data.txt"))) {
String content;
while ((content = bufferedReader.readLine()) != null) {
System.out.println(content);
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
6. So sánh chi tiết
Theo dõi bảng so sánh dưới đây để thấy rõ ưu điểm của try-with-resources:
- Độ dài mã:
try-with-resourcesngắn gọn hơn, không cần khốifinallythủ công. - Xử lý ngoại lệ: Với
try-finally, ngoại lệ từclose()có thể che mất ngoại lệ chính.try-with-resourcesghi nhận ngoại lệ từclose()dưới dạngSuppressed Exception, không làm mất thông tin lỗi gốc. - Độ an toàn:
try-with-resourcestự động hóa việc đóng tài nguyên, giảm thiểu nguy cơ rò rỉ do lỗi con người.