อะไรคือความแตกต่างระหว่าง
try { }
catch
{ throw; }
และ
try { }
catch(Exception e)
{ throw e;}
เหรอ?
และควรใช้เมื่อใด
อะไรคือความแตกต่างระหว่าง
try { }
catch
{ throw; }
และ
try { }
catch(Exception e)
{ throw e;}
เหรอ?
และควรใช้เมื่อใด
คำตอบ:
การก่อสร้าง
try { ... }
catch () { ... } /* You can even omit the () here */
try { ... }
catch (Exception e) { ... }
มีความคล้ายคลึงกันตรงที่ทั้งสองจะจับทุกข้อยกเว้นที่โยนเข้าไปในtry
บล็อก (และควรหลีกเลี่ยงเว้นแต่คุณจะใช้สิ่งนี้เพื่อบันทึกข้อยกเว้นเท่านั้น) ตอนนี้ดูสิ่งเหล่านี้:
try { ... }
catch ()
{
/* ... */
throw;
}
try { ... }
catch (Exception e)
{
/* ... */
throw;
}
try { ... }
catch (Exception e)
{
/* ... */
throw e;
}
บล็อกการลองจับครั้งแรกและครั้งที่สองนั้นเหมือนกันทุกประการเพียงแค่สร้างข้อยกเว้นปัจจุบันขึ้นมาใหม่และข้อยกเว้นนั้นจะเก็บ "แหล่งที่มา" และการติดตามสแต็กไว้
บล็อกลองจับที่สามแตกต่างกัน เมื่อมันพ่นข้อยกเว้นมันจะเปลี่ยนแหล่งที่มาและการติดตามสแต็กเพื่อให้ดูเหมือนว่าข้อยกเว้นถูกโยนออกไปจากวิธีนี้จากบรรทัดนั้นthrow e
บนเมธอดที่มีบล็อก try-catch นั้น
คุณควรใช้อันไหน? จริงๆมันขึ้นอยู่กับแต่ละกรณี
สมมติว่าคุณมีไฟล์ Person
คลาสที่มี.Save()
วิธีการที่จะคงอยู่ในฐานข้อมูล สมมติว่าแอปพลิเคชันของคุณดำเนินการตามPerson.Save()
วิธีการใดที่หนึ่ง หากฐานข้อมูลของคุณปฏิเสธที่จะช่วยชีวิตบุคคลนั้น.Save()
จะทำให้เกิดข้อยกเว้น คุณควรใช้throw
หรือthrow e
ในกรณีนี้? มันขึ้นอยู่กับ
สิ่งที่ฉันชอบคือทำ:
try {
/* ... */
person.Save();
}
catch(DBException e) {
throw new InvalidPersonException(
"The person has an invalid state and could not be saved!",
e);
}
สิ่งนี้ควรทำให้ DBException เป็น "Inner Exception" ของข้อยกเว้นที่ใหม่กว่าที่กำลังโยน ดังนั้นเมื่อคุณตรวจสอบ InvalidPersonException นี้การติดตามสแต็กจะมีข้อมูลกลับไปยังเมธอด Save (ซึ่งอาจเพียงพอสำหรับคุณในการแก้ปัญหา) แต่คุณยังคงสามารถเข้าถึงข้อยกเว้นเดิมได้หากคุณต้องการ
ในคำพูดสุดท้ายเมื่อคุณคาดว่าจะมีข้อยกเว้นคุณควรจับข้อยกเว้นเฉพาะข้อนั้นจริงๆไม่ใช่ข้อยกเว้นทั่วไปException
กล่าวคือหากคุณคาดหวัง InvalidPersonException คุณควรต้องการ:
try { ... }
catch (InvalidPersonException e) { ... }
ถึง
try { ... }
catch (Exception e) { ... }
โชคดี!
ขั้นแรกจะรักษาการติดตามสแต็กในขณะที่วินาทีรีเซ็ต ซึ่งหมายความว่าหากคุณใช้แนวทางที่สองการติดตามสแต็กของข้อยกเว้นจะเริ่มต้นจากวิธีนี้เสมอและคุณจะสูญเสียการติดตามข้อยกเว้นดั้งเดิมซึ่งอาจเป็นหายนะสำหรับคนที่อ่านบันทึกข้อยกเว้นเนื่องจากเขาจะไม่พบสาเหตุดั้งเดิมของข้อยกเว้น .
แนวทางที่สองอาจเป็นประโยชน์เมื่อคุณต้องการเพิ่มข้อมูลเพิ่มเติมในการติดตามสแต็ก แต่จะใช้ในลักษณะนี้:
try
{
// do something
}
catch (Exception ex)
{
throw new Exception("Additional information...", ex);
}
มีบล็อกโพสต์เกี่ยวกับความแตกต่าง
throw
throw e
คุณควรใช้
try { }
catch(Exception e)
{ throw }
หากคุณต้องการทำบางสิ่งโดยมีข้อยกเว้นก่อนที่จะโยนมันอีกครั้ง (เช่นบันทึกข้อมูล) การโยนแบบโดดเดี่ยวจะรักษาร่องรอยของสแต็ก
ความแตกต่างระหว่างตัวจับแบบไม่มีพารามิเตอร์และ catch(Exception e)
คือคุณได้รับการอ้างอิงถึงข้อยกเว้น จากเฟรมเวิร์กเวอร์ชัน 2 ที่ไม่มีการจัดการข้อยกเว้นจะรวมอยู่ในข้อยกเว้นที่มีการจัดการดังนั้นข้อยกเว้นที่ไม่มีพารามิเตอร์จะไม่มีประโยชน์สำหรับสิ่งใด ๆ อีกต่อไป
ความแตกต่างระหว่างthrow;
และthrow e;
คือข้อแรกใช้เพื่อลบข้อยกเว้นใหม่และข้อที่สองใช้เพื่อโยนข้อยกเว้นที่สร้างขึ้นใหม่ หากคุณใช้ข้อยกเว้นที่สองเพื่อสร้างข้อยกเว้นขึ้นมาใหม่จะถือว่าเป็นข้อยกเว้นใหม่และแทนที่ข้อมูลสแต็กทั้งหมดจากที่ที่เคยถูกโยนทิ้งไป
ดังนั้นคุณไม่ควรใช้ทางเลือกใดทางเลือกหนึ่งในคำถาม คุณไม่ควรใช้ตัวจับแบบไม่มีพารามิเตอร์และคุณควรใช้throw;
เพื่อลบข้อยกเว้นใหม่
นอกจากนี้ในกรณีส่วนใหญ่คุณควรใช้คลาสข้อยกเว้นที่เฉพาะเจาะจงมากกว่าคลาสพื้นฐานสำหรับข้อยกเว้นทั้งหมด คุณควรจับเฉพาะข้อยกเว้นที่คุณคาดการณ์ไว้เท่านั้น
try {
...
} catch (IOException e) {
...
throw;
}
หากคุณต้องการเพิ่มข้อมูลใด ๆ เมื่อสร้างข้อยกเว้นใหม่ให้สร้างข้อยกเว้นใหม่โดยให้ข้อยกเว้นเดิมเป็นข้อยกเว้นภายในเพื่อเก็บรักษาข้อมูลทั้งหมด:
try {
...
} catch (IOException e) {
...
throw new ApplicationException("Some informative error message", e);
}