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 AutoCloseable
tà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 FileWriter
và a BufferedWriter
bao 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ố AutoCloseable
tà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ở FileWriter
không được khai báo trong một biến, nó sẽ không bao giờ được đóng trực tiếp trong finally
khối được tạo . Nó sẽ được đóng chỉ thông qua các close
phươ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 bw
tạo của nó, thì nó close
sẽ 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 close
có 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 bw
thâ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.
BufferedWriter
xây dựng có thể dễ dàng ném một ngoại lệ. OutOfMemoryError
có 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 flush
của bạn BufferedWriter
nế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ệ). FileWriter
chọ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.