มันสมเหตุสมผลหรือไม่ที่จะทำแบบ“ ลองในที่สุด” โดยไม่“ จับ”


128

ฉันเห็นรหัสบางอย่างเช่นนี้:

    try
    {
        db.store(mydata);
    }
    finally
    {
        db.cleanup();
    }

ฉันคิดว่าtryควรจะมีcatch?

ทำไมโค้ดนี้ถึงทำแบบนี้?


1
ช่วยให้มั่นใจได้ว่าจะล้างข้อมูลตามการตอบสนองอื่น ๆ ที่กล่าวถึงโดยเฉพาะอย่างยิ่งสำหรับการจัดการไฟล์fopenหรือการเชื่อมต่อ DB (ใน PHP)
MediaVince

คำตอบ:


184

สิ่งนี้มีประโยชน์หากคุณต้องการให้วิธีการดำเนินการในปัจจุบันยังคงทิ้งข้อยกเว้นในขณะที่อนุญาตให้ล้างทรัพยากรอย่างเหมาะสม ด้านล่างนี้เป็นตัวอย่างที่เป็นรูปธรรมของการจัดการข้อยกเว้นจากวิธีการโทร

public void yourOtherMethod() {
    try {
        yourMethod();
    } catch (YourException ex) {
        // handle exception
    }
}    

public void yourMethod() throws YourException {
    try {
        db.store(mydata);
    } finally {
        db.cleanup();
    }
}

17
มักใช้กับล็อคเช่น lock.lock (); ลอง {/ * ล็อก * /} ในที่สุด {lock.unlock ()}
นาทีที่

จะเกิดอะไรขึ้นหากข้อยกเว้นถูกโยนเข้าไปในที่สุด?
บาร์

1
@barth เมื่อไม่มีการcatchบล็อกข้อยกเว้นที่เกิดขึ้นfinallyจะถูกดำเนินการก่อนข้อยกเว้นใด ๆ ในtryบล็อก ดังนั้นหากมีสองข้อยกเว้นหนึ่งtryและเป็นหนึ่งในข้อยกเว้นเพียงคนเดียวที่จะถูกโยนเป็นหนึ่งในfinally finallyลักษณะการทำงานนี้จะไม่เหมือนกันใน PHP และ Python เป็นทั้งข้อยกเว้นจะถูกโยนในเวลาเดียวกันในภาษาเหล่านี้และคำสั่งข้อยกเว้นเป็นครั้งแรกแล้วtry finally
ฝนตก

72

ที่นั่นเป็นเพราะโปรแกรมเมอร์ต้องการให้แน่ใจว่าdb.cleanup()มีการเรียกใช้แม้ว่าโค้ดในบล็อกลองจะมีข้อยกเว้นก็ตาม ข้อยกเว้นใด ๆ จะไม่ได้รับการจัดการโดยบล็อกนั้น แต่จะเผยแพร่ขึ้นไปหลังจากที่บล็อกในที่สุดเสร็จสิ้นแล้ว


23
+1 แน่นอน เป็นเพียงมีเพื่อให้try finallyไม่มีข้อยกเว้น
zockman

2
+1 เพื่อให้ชัดเจนว่าข้อยกเว้นยังคงอยู่ในสแต็กจนกว่าจะถูกจับได้ ขอบคุณ
Code Jockey

20

ทำไมโค้ดนี้ถึงทำแบบนี้?

เนื่องจากเห็นได้ชัดว่าโค้ดไม่ทราบวิธีจัดการกับข้อยกเว้นในระดับนี้ ไม่เป็นไร - ตราบใดที่ผู้โทรคนใดคนหนึ่งทำเช่นตราบใดที่ข้อยกเว้นได้รับการจัดการในที่สุด

บ่อยครั้งรหัสระดับต่ำไม่สามารถตอบสนองต่อข้อยกเว้นได้อย่างเหมาะสมเนื่องจากผู้ใช้จำเป็นต้องได้รับการแจ้งเตือนหรือต้องบันทึกข้อยกเว้นหรือต้องลองใช้กลยุทธ์อื่น โค้ดระดับต่ำจะดำเนินการอย่างใดอย่างหนึ่งฟังก์ชั่นเท่านั้นและไม่ทราบเกี่ยวกับการตัดสินใจในระดับที่สูงขึ้น

แต่โค้ดยังคงต้องการทำความสะอาดทรัพยากร (เพราะถ้าไม่เป็นเช่นนั้นก็จะรั่วไหล) ดังนั้นจึงทำเช่นนั้นในส่วนfinallyคำสั่งเพื่อให้แน่ใจว่าจะเกิดขึ้นเสมอไม่ว่าจะมีข้อยกเว้นหรือไม่ก็ตาม


2

บล็อกสุดท้ายช่วยให้มั่นใจได้ว่าแม้ว่า RuntimeException จะถูกโยนทิ้งไป (อาจเกิดจากข้อผิดพลาดบางอย่างในรหัสที่เรียก) การdb.cleanup()โทรจะถูกสร้างขึ้น

นอกจากนี้ยังมักใช้เพื่อป้องกันการทำรังมากเกินไป:

try
{
    if (foo) return false;
    //bla ...
    return true;
}
finally
{
    //clean up
}

โดยเฉพาะอย่างยิ่งเมื่อมีหลายจุดที่วิธีการส่งคืนสิ่งนี้จะช่วยเพิ่มความสามารถในการอ่านเนื่องจากทุกคนสามารถเห็นรหัสการล้างข้อมูลที่เรียกว่าในทุกกรณี


0

รหัสกำลังทำเพื่อให้แน่ใจว่าฐานข้อมูลถูกปิด
โดยปกติวิธีที่คุณจะทำคือใส่รหัสการเข้าถึงฐานข้อมูลทั้งหมดของคุณในบล็อกลองจากนั้นจึงทำการโทรเพื่อปิดฐานข้อมูลในบล็อกสุดท้าย
วิธีลอง ... ในที่สุดก็ใช้งานได้หมายความว่าโค้ดในบล็อกลองถูกรันและโค้ดในบล็อกสุดท้ายจะทำงานเมื่อเสร็จสิ้น ... ไม่ว่าจะเกิดอะไรขึ้น
สั้น ๆ ของคอมพิวเตอร์ที่ถูกดึงออกจากผนังในที่สุดก็จะดำเนินการ
ซึ่งหมายความว่าแม้ว่าจะมีการเรียกข้อยกเว้นและวิธีการนี้ใช้เวลาสามปีในการดำเนินการ แต่ก็จะยังคงอยู่ในบล็อกสุดท้ายและฐานข้อมูลจะถูกปิด


0

หากรหัสใด ๆ ในบล็อก try สามารถทำให้เกิดข้อยกเว้นที่ตรวจสอบได้รหัสนั้นจะต้องปรากฏในส่วนคำสั่งพ่นของลายเซ็นวิธีการ หากข้อยกเว้นที่ไม่ได้ทำเครื่องหมายถูกโยนออกไปข้อยกเว้นนั้นจะถูกทำให้เกิดฟองออกจากวิธีการ

สุดท้ายบล็อกจะถูกดำเนินการเสมอไม่ว่าจะมีข้อยกเว้นหรือไม่ก็ตาม

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.