ไวยากรณ์ของJava 7 try-with-resources (หรือที่รู้จักในชื่อ ARM block ( การจัดการทรัพยากรอัตโนมัติ )) เป็นสิ่งที่ดีสั้นและตรงไปตรงมาเมื่อใช้AutoCloseable
ทรัพยากรเพียงแหล่งเดียว อย่างไรก็ตามฉันไม่แน่ใจว่าสำนวนที่ถูกต้องคืออะไรเมื่อฉันต้องการประกาศหลาย ๆ ทรัพยากรที่ต้องพึ่งพาซึ่งกันและกันตัวอย่างเช่น a FileWriter
และ a BufferedWriter
ที่ล้อมรอบ แน่นอนว่าคำถามนี้เกี่ยวข้องกับกรณีใด ๆ เมื่อAutoCloseable
มีการห่อทรัพยากรไม่เฉพาะชั้นเรียนเฉพาะสองแห่งนี้
ฉันมากับทางเลือกทั้งสามต่อไปนี้:
1)
สำนวนไร้เดียงสาที่ฉันเห็นคือประกาศเฉพาะเสื้อคลุมระดับบนสุดในตัวแปรที่จัดการโดย ARM:
static void printToFile1(String text, File file) {
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
อันนี้ดีและสั้น แต่มันก็หัก เนื่องจากพื้นฐานFileWriter
ไม่ได้ถูกประกาศในตัวแปรมันจะไม่ถูกปิดโดยตรงในfinally
บล็อกที่สร้างขึ้น มันจะถูกปิดโดยclose
วิธีการห่อBufferedWriter
เท่านั้น ปัญหาคือว่าถ้ายกเว้นจะโยนจากbw
คอนสตรัค 's มันclose
จะไม่ถูกเรียกและดังนั้นจึงพื้นฐานจะไม่ถูกปิดFileWriter
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
}
}
ที่นี่ทั้งทรัพยากรพื้นฐานและทรัพยากรห่อถูกประกาศในตัวแปรที่จัดการโดย ARM ดังนั้นทั้งสองอย่างจะปิดอย่างแน่นอน แต่ข้อมูลพื้นฐานfw.close()
จะถูกเรียกสองครั้ง : ไม่เพียงโดยตรง แต่ยังผ่านการตัดคำbw.close()
ด้วย
นี่ไม่ควรเป็นปัญหาสำหรับคลาสเฉพาะสองเหล่านี้ที่ทั้งสองนำมาใช้Closeable
(ซึ่งเป็นชนิดย่อยของAutoCloseable
), ซึ่งสัญญาระบุว่าclose
อนุญาตให้มีการโทรหลายสายได้:
ปิดสตรีมนี้และปล่อยทรัพยากรระบบใด ๆ ที่เกี่ยวข้อง หากกระแสข้อมูลถูกปิดอยู่แล้วการเรียกใช้วิธีนี้จะไม่มีผลกระทบ
อย่างไรก็ตามในกรณีทั่วไปฉันสามารถมีทรัพยากรที่ใช้งานได้เท่านั้นAutoCloseable
(และไม่Closeable
) ซึ่งไม่รับประกันว่าclose
สามารถเรียกได้หลายครั้ง:
โปรดทราบว่าแตกต่างจากวิธีการปิดของ java.io.Closeable วิธีการปิดนี้ไม่จำเป็นต้องเป็น idempotent กล่าวอีกนัยหนึ่งการเรียกใช้วิธีการปิดนี้มากกว่าหนึ่งครั้งอาจมีผลข้างเคียงที่มองเห็นได้ซึ่งแตกต่างจาก Closeable.close ซึ่งจำเป็นต้องมีผลถ้าเรียกว่ามากกว่าหนึ่งครั้ง อย่างไรก็ตามอินเทอร์เฟซของอินเทอร์เฟซนี้ได้รับการสนับสนุนอย่างยิ่งเพื่อให้วิธีการปิด idempotent ของพวกเขา
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
}
}
รุ่นนี้ควรถูกต้องตามหลักวิชาเพราะเพียงfw
แสดงถึงทรัพยากรจริงที่จำเป็นต้องทำความสะอาด bw
ไม่ได้ตัวเองถือทรัพยากรใด ๆ ก็เพียงได้รับมอบหมายไปดังนั้นจึงควรจะเพียงพอที่จะเพียงใกล้พื้นฐานfw
fw
ในทางตรงกันข้ามไวยากรณ์นั้นค่อนข้างผิดปกติและ Eclipse ก็ออกคำเตือนซึ่งฉันเชื่อว่าเป็นสัญญาณเตือนที่ผิด แต่ก็ยังคงเป็นคำเตือนว่ามีการจัดการกับ:
การรั่วไหลของทรัพยากร: 'bw' ไม่เคยถูกปิด
ดังนั้นวิธีการที่จะไปเพื่อ? หรือว่าฉันคิดถึงสำนวนอื่นที่ถูกต้อง ?
public BufferedWriter(Writer out, int sz)
IllegalArgumentException
นอกจากนี้ฉันสามารถขยาย BufferedWriter ด้วยคลาสที่จะโยนบางสิ่งบางอย่างจากตัวสร้างหรือสร้าง wrapper แบบกำหนดเองใด ๆ ที่ฉันต้องการ
BufferedWriter
สร้างสามารถโยนข้อยกเว้นได้อย่างง่ายดาย OutOfMemoryError
อาจเป็นสิ่งที่พบได้บ่อยที่สุดในขณะที่จัดสรรหน่วยความจำที่พอเหมาะสำหรับบัฟเฟอร์ (แม้ว่าอาจระบุว่าคุณต้องการรีสตาร์ทกระบวนการทั้งหมด) / คุณจำเป็นต้องflush
ของคุณBufferedWriter
ถ้าคุณทำไม่ได้ใกล้ชิดและต้องการให้เนื้อหา (โดยทั่วไปเฉพาะกรณีที่ไม่ใช่ข้อยกเว้น) FileWriter
รับสิ่งที่เกิดขึ้นเป็นการเข้ารหัสไฟล์ "เริ่มต้น" ดีกว่าที่จะชัดเจน