ไวยากรณ์ของ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ไม่ได้ตัวเองถือทรัพยากรใด ๆ ก็เพียงได้รับมอบหมายไปดังนั้นจึงควรจะเพียงพอที่จะเพียงใกล้พื้นฐานfwfw
ในทางตรงกันข้ามไวยากรณ์นั้นค่อนข้างผิดปกติและ Eclipse ก็ออกคำเตือนซึ่งฉันเชื่อว่าเป็นสัญญาณเตือนที่ผิด แต่ก็ยังคงเป็นคำเตือนว่ามีการจัดการกับ:
การรั่วไหลของทรัพยากร: 'bw' ไม่เคยถูกปิด
ดังนั้นวิธีการที่จะไปเพื่อ? หรือว่าฉันคิดถึงสำนวนอื่นที่ถูกต้อง ?
public BufferedWriter(Writer out, int sz) IllegalArgumentExceptionนอกจากนี้ฉันสามารถขยาย BufferedWriter ด้วยคลาสที่จะโยนบางสิ่งบางอย่างจากตัวสร้างหรือสร้าง wrapper แบบกำหนดเองใด ๆ ที่ฉันต้องการ
BufferedWriterสร้างสามารถโยนข้อยกเว้นได้อย่างง่ายดาย OutOfMemoryErrorอาจเป็นสิ่งที่พบได้บ่อยที่สุดในขณะที่จัดสรรหน่วยความจำที่พอเหมาะสำหรับบัฟเฟอร์ (แม้ว่าอาจระบุว่าคุณต้องการรีสตาร์ทกระบวนการทั้งหมด) / คุณจำเป็นต้องflushของคุณBufferedWriterถ้าคุณทำไม่ได้ใกล้ชิดและต้องการให้เนื้อหา (โดยทั่วไปเฉพาะกรณีที่ไม่ใช่ข้อยกเว้น) FileWriterรับสิ่งที่เกิดขึ้นเป็นการเข้ารหัสไฟล์ "เริ่มต้น" ดีกว่าที่จะชัดเจน