ทำไมเราถึงใช้บล็อกในที่สุด?


91

เท่าที่ฉันสามารถบอกได้ข้อมูลโค้ดทั้งสองต่อไปนี้จะมีจุดประสงค์เดียวกัน ทำไมต้องfinallyบล็อกเลย?

รหัส A:

try { /* Some code */ }
catch { /* Exception handling code */ }
finally { /* Cleanup code */ }

รหัส B:

try { /* Some code */ }
catch { /* Exception handling code */ }
// Cleanup code

นี่ไม่ได้เจาะจงเฉพาะ C # แต่เป็นคำถาม. Net
Sruly

1
ไม่จำเป็นอีกต่อไปด้วย java7: AutomaticResourceManagement ลอง (new resourceDeclartion ()) {}
Kanagavelu Sugumar

คำตอบ:


140
  • จะเกิดอะไรขึ้นหากข้อยกเว้นที่คุณไม่ได้จัดการถูกโยนทิ้ง? (ฉันหวังว่าคุณจะไม่จับThrowable... )
  • จะเกิดอะไรขึ้นถ้าคุณกลับมาจากข้างใน try block?
  • จะเกิดอะไรขึ้นหากบล็อกจับส่งข้อยกเว้น

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


50
ไม่จำเป็นต้องเป็นจริง ในที่สุดจะไม่ได้รับการดำเนินการหาก (1) มีการSystem.exit()โทร (2) มีการวนซ้ำที่ไม่สิ้นสุดในการลองหรือหนึ่งในบล็อกจับ (3) ฉันดึงปลั๊กบนคอมพิวเตอร์
NullUserException

2
@ อลอง {กลับ 1; } ในที่สุด {เริ่มใหม่ 2; } คุณจะได้รับ 2
Dennis C

19
@NullUserException: ดังนั้นบิต "modulo สองสามวิธี ... "
Jon Skeet

2
John Skeet อาศัยอยู่ที่นี่บน stackoverflow ทุกคำถามเหมือนเสียงกริ่งประตูที่เขาต้องตอบ :)
naikus

1
โพสต์นี้กล่าวถึงเงื่อนไข (หายาก) ที่สุดท้ายจะไม่ถูกเรียก
Candamir

13

โปรดทราบว่า (อย่างน้อยใน Java อาจเป็น C # ด้วย) ก็เป็นไปได้ที่จะมีtryบล็อกที่ไม่มี a catchแต่มีไฟล์finally. เมื่อมีข้อยกเว้นเกิดขึ้นในtryบล็อกโค้ดในfinallyบล็อกจะทำงานก่อนที่ข้อยกเว้นจะสูงขึ้น:

InputStream in = new FileInputStream("somefile.xyz");
try {
    somethingThatMightThrowAnException();
}
finally {
    // cleanup here
    in.close();
}

7

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

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

ตัวอย่างเช่น:

conn c1 = new connection();
try {
    c1.dosomething();
} catch (ExceptionA exa) {
    handleexA();
    //c1.close();
} catch (ExceptionB exb) {
    handleexB();
    //c1.close();
} finally {
    c1.close();
}

1
จะเกิดอะไรขึ้นถ้าฉันไม่ใช้ 'สุดท้าย' แต่ปิดการเชื่อมต่อ?
Istiaque Ahmed

5

สุดท้ายจะถูกเรียกใช้งานเสมอโดยที่โค้ดของคุณหลังจากการจับอาจไม่ได้


1
ทำไมจะไม่ล่ะ! หากข้อยกเว้นได้รับการจัดการอย่างถูกต้องรหัสจะถูกดำเนินการอย่างแน่นอน
Mohammad Nadeem

1
@Nadeem: ดูคำตอบของฉันด้วยเหตุผล 3 ประการที่อาจไม่เกิดขึ้น
Jon Skeet

2

แม้ว่าแอปพลิเคชันของเราจะปิดอย่างมีประสิทธิภาพ แต่ก็มีงานบางอย่างที่เราต้องดำเนินการ (เช่นการปล่อยหน่วยความจำการปิดฐานข้อมูลการล็อกการปลดล็อก ฯลฯ ) หากคุณเขียนโค้ดเหล่านี้ลงในfinallyบล็อกมันจะดำเนินการไม่ว่าจะมีข้อยกเว้นหรือ ไม่...

แอปพลิเคชันของคุณอาจเป็นชุดของเธรดExceptionยุติเธรด แต่ไม่ใช่แอปพลิเคชันทั้งหมดในกรณีนี้finallyจะมีประโยชน์มากกว่า

ในบางกรณีfinallyจะไม่ดำเนินการเช่น JVM Fail, Thread terminate เป็นต้น


1

เนื่องจากคุณต้องใช้รหัสนั้นเพื่อดำเนินการโดยไม่คำนึงถึงข้อยกเว้นใด ๆ ที่อาจเกิดขึ้น ตัวอย่างเช่นคุณอาจต้องล้างทรัพยากรที่ไม่มีการจัดการบางส่วน (การสร้าง 'ใช้' คอมไพล์เพื่อลอง / บล็อกในที่สุด)


1

ยังคงเลื่อนลง? จัดไป!

คำถามนี้ทำให้ฉันมีช่วงเวลาที่ยากลำบาก

try
{
 int a=1;
 int b=0;
 int c=a/b;
}
catch(Exception ex)
{
 console.writeline(ex.Message);
}
finally
{
 console.writeline("Finally block");
}
console.writeline("After finally");

จะพิมพ์อะไรในสถานการณ์ข้างต้น? ใช่เดาถูก:

  • เช่นข้อความ - ไม่ว่าจะเป็นอะไรก็ตาม (อาจพยายามหารด้วยศูนย์)

  • สุดท้ายบล็อก

  • หลังจากในที่สุด

    try
    {
        int a=1;
        int b=0;
        int c=a/b;
    }
    catch(Exception ex)
    {
        throw(ex);
    }
    finally
    {
        console.writeline("Finally block");
    }
    console.writeline("After finally");
    

นี่จะพิมพ์อะไร ไม่มีอะไร! มันแสดงข้อผิดพลาดเนื่องจากบล็อกการจับทำให้เกิดข้อผิดพลาด

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

try
{    
 try
    {
     int a=1;
     int b=0;
     int c=a/b;
    }
    catch(Exception ex)
    {
     throw(ex);
    }
    finally
    {
     console.writeline("Finally block")
    }
    console.writeline("After finally");
}
catch(Exception ex)
{
 console.writeline(ex.Message);
}

ในกรณีนี้ผลลัพธ์จะเป็น:

  • สุดท้ายบล็อก
  • เช่นข้อความ - ไม่ว่าจะเป็นอะไรก็ตาม

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

ตอนนี้คุณรู้แล้วว่าทำไมไม่ปิดทรัพยากรของคุณด้วยรหัสหลังจากบล็อกจับวางไว้ในบล็อกในที่สุด


0

อาจมีบางครั้งที่คุณต้องการรันโค้ดไม่ว่าจะเกิดอะไรขึ้นก็ตาม ไม่ว่าจะมีข้อยกเว้นเกิดขึ้นหรือไม่ finallyจากนั้นหนึ่งในการใช้งาน


0

finallyดำเนินการเสมอเว้นแต่ JVM จะปิดตัวลงfinallyเพียงแค่ให้วิธีการใส่รหัสล้างข้อมูลไว้ในที่เดียว

มันจะน่าเบื่อเกินไปถ้าคุณต้องใส่รหัสทำความสะอาดในแต่ละcatchบล็อก


0

หากบล็อก catch มีข้อยกเว้นใด ๆ โค้ดที่เหลือจะไม่ทำงานดังนั้นเราต้องเขียนบล็อกสุดท้าย


0

ในที่สุด block ใน java สามารถใช้เพื่อใส่รหัส "cleanup" เช่นปิดไฟล์ปิดการเชื่อมต่อเป็นต้น


บล็อกสุดท้ายจะไม่ถูกดำเนินการหากโปรแกรมออก (ไม่ว่าจะโดยการเรียก System.exit () หรือทำให้เกิดข้อผิดพลาดร้ายแรงที่ทำให้กระบวนการยกเลิก)

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