Cú pháp thử tài nguyên Java 7 (còn được gọi là khối ARM ( Quản lý tài nguyên tự động )) rất hay, ngắn gọn và đơn giản khi chỉ sử dụng một AutoCloseabletài nguyên. Tuy nhiên, tôi không chắc đâu là thành ngữ chính xác khi tôi cần khai báo nhiều tài nguyên phụ thuộc lẫn nhau, ví dụ a FileWritervà a BufferedWriterbao bọc nó. Tất nhiên, câu hỏi này liên quan đến bất kỳ trường hợp nào khi một số AutoCloseabletài nguyên được gói, không chỉ hai lớp cụ thể này.
Tôi đã đưa ra ba phương án sau:
1)
Thành ngữ ngây thơ mà tôi đã thấy là chỉ khai báo trình bao bọc cấp cao nhất trong biến do ARM quản lý:
static void printToFile1(String text, File file) {
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
Điều này là tốt đẹp và ngắn, nhưng nó bị hỏng. Bởi vì cơ sở FileWriterkhông được khai báo trong một biến, nó sẽ không bao giờ được đóng trực tiếp trong finallykhối được tạo . Nó sẽ được đóng chỉ thông qua các closephương pháp của gói BufferedWriter. Vấn đề là, nếu một ngoại lệ được ném ra từ hàm bwtạo của nó, thì nó closesẽ không được gọi và do đó phần bên dưới FileWriter sẽ không bị đóng .
2)
static void printToFile2(String text, File file) {
try (FileWriter fw = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw)) {
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
Ở đây, cả tài nguyên gói và tài nguyên gói được khai báo trong các biến do ARM quản lý, vì vậy cả hai tài nguyên này chắc chắn sẽ bị đóng, nhưng phần bên dưới fw.close() sẽ được gọi hai lần : không chỉ trực tiếp mà còn thông qua gói bw.close().
Đây không phải là một vấn đề đối với hai lớp cụ thể mà cả hai thực hiện Closeable(là một kiểu con của AutoCloseable), có hợp đồng nói rằng nhiều cuộc gọi closeđược phép:
Đóng luồng này và giải phóng bất kỳ tài nguyên hệ thống nào được liên kết với nó. Nếu luồng đã bị đóng thì việc gọi phương thức này không có hiệu lực.
Tuy nhiên, trong trường hợp chung, tôi có thể có các tài nguyên chỉ thực hiện AutoCloseable(chứ không phải Closeable), điều này không đảm bảo closecó thể được gọi nhiều lần:
Lưu ý rằng không giống như phương thức đóng của java.io.Closizable, phương thức đóng này không bắt buộc phải là idempotent. Nói cách khác, gọi phương thức đóng này nhiều lần có thể có một số tác dụng phụ có thể nhìn thấy, không giống như Closizable.close được yêu cầu không có hiệu lực nếu được gọi nhiều lần. Tuy nhiên, những người triển khai giao diện này được khuyến khích mạnh mẽ để làm cho các phương thức gần gũi của họ trở nên bình thường.
3)
static void printToFile3(String text, File file) {
try (FileWriter fw = new FileWriter(file)) {
BufferedWriter bw = new BufferedWriter(fw);
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
Phiên bản này phải đúng về mặt lý thuyết, bởi vì chỉ có fwđại diện cho một tài nguyên thực sự cần được làm sạch. Bản bwthân nó không nắm giữ bất kỳ tài nguyên nào, nó chỉ ủy thác cho fw, vì vậy nó chỉ đủ để đóng cơ sở fw.
Mặt khác, cú pháp hơi bất thường và đồng thời, Eclipse đưa ra cảnh báo, mà tôi tin là cảnh báo sai, nhưng nó vẫn là một cảnh báo mà người ta phải xử lý:
Tài nguyên bị rò rỉ: 'bw' không bao giờ bị đóng
Vì vậy, cách tiếp cận nào để đi? Hoặc tôi đã bỏ lỡ một số thành ngữ khác đó là một thành ngữ chính xác ?
public BufferedWriter(Writer out, int sz)có thể ném một IllegalArgumentException. Ngoài ra, tôi có thể mở rộng BufferedWriter với một lớp sẽ ném thứ gì đó từ hàm tạo của nó hoặc tạo bất kỳ trình bao bọc tùy chỉnh nào tôi cần.
BufferedWriterxây dựng có thể dễ dàng ném một ngoại lệ. OutOfMemoryErrorcó lẽ là phổ biến nhất vì nó phân bổ một đoạn bộ nhớ hợp lý cho bộ đệm (mặc dù có thể cho thấy bạn muốn khởi động lại toàn bộ quá trình). / Bạn cần flushcủa bạn BufferedWriternếu bạn không gần gũi và muốn giữ lại các nội dung (thường chỉ những trường hợp không ngoại lệ). FileWriterchọn bất cứ điều gì xảy ra để mã hóa tệp "mặc định" - tốt hơn là nên rõ ràng.