การจับข้อยกเว้นทั่วไปเป็นสิ่งที่ไม่ดีจริง ๆ หรือ


56

ฉันมักจะเห็นด้วยกับคำเตือนการวิเคราะห์รหัสส่วนใหญ่และฉันพยายามที่จะปฏิบัติตามพวกเขา อย่างไรก็ตามฉันมีเวลายากขึ้นกับสิ่งนี้:

CA1031: อย่าตรวจจับชนิดข้อยกเว้นทั่วไป

ฉันเข้าใจเหตุผลของกฎนี้ แต่ในทางปฏิบัติถ้าฉันต้องการที่จะทำสิ่งเดียวกันโดยไม่คำนึงถึงข้อยกเว้นที่ถูกโยนออกไปทำไมฉันต้องจัดการแต่ละอย่างโดยเฉพาะ? นอกจากนี้หากฉันจัดการข้อยกเว้นเฉพาะจะเกิดอะไรขึ้นถ้ารหัสที่ฉันเรียกจะเปลี่ยนแปลงเพื่อให้เกิดข้อยกเว้นใหม่ในอนาคต ตอนนี้ฉันต้องเปลี่ยนรหัสเพื่อจัดการข้อยกเว้นใหม่นั้น ในขณะที่ถ้าฉันเพียงแค่จับExceptionรหัสของฉันไม่ต้องเปลี่ยน

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

อาจเป็นตัวอย่างที่ดีกว่า:

public void Foo()
{
    // Some logic here.
    LogUtility.Log("some message");
}

public static void Log()
{
    try
    {
        // Actual logging here.
    }
    catch (Exception ex)
    {
        // Eat it. Logging failures shouldn't stop us from processing.
    }
}

หากคุณไม่ได้รับการยกเว้นทั่วไปที่นี่คุณต้องรับการยกเว้นทุกประเภทที่เป็นไปได้ Patrick มีจุดดีที่OutOfMemoryExceptionไม่ควรจัดการด้วยวิธีนี้ แล้วถ้าฉันต้องการเพิกเฉยทุกข้อยกเว้นOutOfMemoryExceptionล่ะ?


12
เกี่ยวกับOutOfMemoryExceptionอะไร รหัสการจัดการเช่นเดียวกับทุกอย่างอื่น?
แพทริค

@ แพทริกจุดดี ฉันได้เพิ่มตัวอย่างใหม่ในคำถามของฉันเพื่อครอบคลุมคำถามของคุณ
บ็อบฮอร์น

1
การจับข้อยกเว้นทั่วไปนั้นไม่ดีเท่ากับการสร้างข้อความทั่วไปเกี่ยวกับสิ่งที่ทุกคนควรทำ โดยทั่วไปแล้วไม่มีวิธีใดที่เหมาะกับทุกคน

4
@ แพทริกที่จะเป็นOutOfMemoryErrorซึ่งเป็นแยกออกจากExceptionต้นไม้มรดกด้วยเหตุผลอย่างที่
Darkhogg

ข้อยกเว้นเกี่ยวกับคีย์บอร์ดเช่น Ctrl-Alt-Del คืออะไร
Mawg

คำตอบ:


33

โดยทั่วไปกฎเหล่านี้เป็นความคิดที่ดีและควรปฏิบัติตาม

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

บนเคาน์เตอร์ด้านของการโต้แย้ง

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


2
เห็นพ้อง ที่มากอย่างน้อยตอนนี้ที่เข้าสู่ระบบปกติครับทำให้ชนิดของบทบัญญัติบางอย่างที่จะให้บางชนิดของการแก้จุดบกพร่องการส่งออกไปยัง stderr ถ้าไม่มีอะไรอื่น
Shadur

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

1
น่าสนใจเนื่องจาก log4net ไม่ต้องการหยุดแอปเพียงเพราะการบันทึกล้มเหลว และฉันคิดว่ามันขึ้นอยู่กับสิ่งที่คุณกำลังบันทึก; ตรวจสอบความปลอดภัยแน่นอนฆ่ากระบวนการ แต่บันทึกการแก้ปัญหา? ไม่ค่อยสำคัญ.
แอนดี้

1
@Andy: ใช่ทุกอย่างขึ้นอยู่กับสิ่งที่คุณทำ
Martin York

2
ทำไมคุณไม่เข้าใจพวกเขา และคุณไม่ควรพยายามทำเช่นนั้น?
Mawg

31

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

มีข้อยกเว้นบางประการที่คุณสามารถจัดการได้:

  • ข้อยกเว้นร้ายแรง : หน่วยความจำไม่เพียงพอสแต็คล้นเป็นต้นพลังเหนือธรรมชาติบางอย่างทำให้จักรวาลของคุณยุ่งเหยิงและกระบวนการกำลังจะตาย คุณไม่สามารถทำให้สถานการณ์ดีขึ้นได้ดังนั้นอย่ายอมแพ้
  • มีข้อผิดพลาดเกิดขึ้นเนื่องจากข้อบกพร่องในรหัสที่คุณใช้ : อย่าพยายามจัดการมัน แต่ควรแก้ไขที่มาของปัญหา อย่าใช้ข้อยกเว้นสำหรับการควบคุมการไหล
  • สถานการณ์เจ๋ง : จัดการข้อยกเว้นเฉพาะในกรณีเหล่านี้เท่านั้น ที่นี่เราสามารถรวม: ปลั๊กสายเคเบิลเครือข่ายการเชื่อมต่ออินเทอร์เน็ตหยุดทำงานการอนุญาตที่ขาดหายไป ฯลฯ

โอ้และเป็นกฎทั่วไป: ถ้าคุณไม่รู้ว่าจะทำอย่างไรกับข้อยกเว้นถ้าคุณจับมันก็จะดีกว่าที่จะล้มเหลวอย่างรวดเร็ว (ผ่านข้อยกเว้นเพื่อโทรและให้มันจัดการ)


1
กรณีเฉพาะในคำถามคืออะไร หากมีข้อผิดพลาดในรหัสการบันทึกอาจเป็นไปได้ที่จะเพิกเฉยข้อยกเว้นเนื่องจากรหัสที่มีความสำคัญจริง ๆ ไม่ควรได้รับผลกระทบจากสิ่งนั้น
svick

4
ทำไมไม่แก้ไขข้อผิดพลาดในรหัสการบันทึกแทน?
Victor Hurdugaci

3
ผู้ชนะมันอาจไม่ใช่ข้อผิดพลาด หากดิสก์ที่บันทึกการใช้งานหมดพื้นที่ข้อผิดพลาดในรหัสการบันทึกคืออะไร?
Carson63000

4
@ Carson63000 - ใช่ บันทึกไม่ถูกเขียนดังนั้น: bug ใช้บันทึกการหมุนขนาดคงที่
detly

5
นี่คือคำตอบที่ดีที่สุด IMO แต่มันก็จะหายไปหนึ่งด้านที่สำคัญ: การรักษาความปลอดภัย มีข้อยกเว้นบางประการที่เกิดขึ้นเป็นผลมาจากคนร้ายพยายามฉ้อโกงโปรแกรมของคุณ หากมีข้อผิดพลาดเกิดขึ้นที่คุณไม่สามารถจัดการได้คุณจะไม่สามารถเชื่อถือรหัสนั้นได้อีก ไม่มีใครชอบที่จะได้ยินว่าพวกเขาเขียนรหัสที่ให้คนเลวเข้ามา
riwalk

15

วงนอกชั้นบนสุดควรมีสิ่งใดสิ่งหนึ่งที่สามารถพิมพ์ได้แล้วตายอย่างน่ากลัวความรุนแรงและความตายของ NOISY (เพราะสิ่งนี้ไม่ควรเกิดขึ้นและมีคนต้องการได้ยิน)

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


1
ฉันเห็นด้วยกับสิ่งนี้ในทางทฤษฎี แต่สิ่งที่เกี่ยวกับตัวอย่างการบันทึกของฉันข้างต้น ถ้าคุณไม่ต้องการละเว้นข้อยกเว้นการบันทึกและทำต่อไป คุณควรจะต้องจับทุกข้อยกเว้นที่อาจถูกโยนและจัดการแต่ละข้อในขณะที่ปล่อยให้เกิดข้อยกเว้นที่รุนแรงขึ้น
บ็อบฮอร์น

6
@BobHorn: ดูสองวิธี ใช่คุณสามารถพูดได้ว่าการบันทึกไม่สำคัญเป็นพิเศษและหากล้มเหลวก็ไม่ควรหยุดแอปของคุณ และนั่นเป็นจุดที่ยุติธรรมพอสมควร แต่ถ้าแอปพลิเคชันของคุณล้มเหลวในการเข้าสู่ระบบเป็นเวลาห้าเดือนและคุณไม่มีความคิด ฉันเคยเห็นสิ่งนี้เกิดขึ้น จากนั้นเราก็ต้องการบันทึก ภัยพิบัติ ฉันขอแนะนำให้ทำทุกสิ่งที่คุณคิดว่าจะหยุดการบันทึกล้มเหลวดีกว่าไม่สนใจเมื่อทำ ( แต่คุณจะไม่ได้รับมากของฉันทามติเกี่ยวกับที่.)
สาธารณรัฐประชาธิปไตยประชาชนลาว

@pdr ในตัวอย่างการบันทึกของฉันฉันมักจะส่งอีเมลแจ้งเตือน หรือเรามีระบบที่ใช้ในการตรวจสอบบันทึกและหากบันทึกไม่ได้ถูกบรรจุอย่างแข็งขันทีมสนับสนุนของเราจะได้รับการแจ้งเตือน ดังนั้นเราจึงตระหนักถึงปัญหาการบันทึกในรูปแบบอื่น ๆ
บ็อบฮอร์น

@ BobHorn ตัวอย่างการบันทึกของคุณค่อนข้างมีการวางแผน - กรอบการบันทึกส่วนใหญ่ที่ฉันรู้จักไปไกลมากไม่ทิ้งข้อยกเว้นใด ๆและจะไม่ถูกเรียกเช่นนั้น (เพราะจะทำให้คำสั่งบันทึกใด ๆ เกิดขึ้นที่บรรทัด X ในไฟล์ Y )

@pdr ฉันได้ตั้งคำถามที่รายการ logback (Java) เกี่ยวกับวิธีที่จะทำให้กรอบการบันทึกหยุดแอปพลิเคชันหากการกำหนดค่าการบันทึกล้มเหลวเพียงเพราะมันสำคัญมากที่เรามีบันทึกและความล้มเหลวเงียบ ๆ ไม่สามารถยอมรับได้ ทางออกที่ดียังอยู่ระหว่างการพิจารณา

9

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


5

ความเป็นไปได้ทั้งสองนั้นไม่ได้มีความพิเศษเฉพาะตัว

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

try
{
    this.Foo();
}
catch (BarException ex)
{
    Console.WriteLine("Foo has barred!");
}
catch (BazException ex)
{
    Console.WriteLine("Foo has bazzed!");
}
catch (Exception ex)
{
    Console.WriteLine("Unknown exception on Foo!");
    throw;
}

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

แก้ไข: ด้วยเหตุผลที่ระบุไว้ในความคิดเห็นให้เพิ่มใหม่ในการจับครั้งสุดท้าย


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

1
@pdr แน่นอนคุณรู้ว่ามันเป็นตัวอย่างที่วางแผนไว้ ประเด็นก็คือการสาธิตการจับข้อยกเว้นทั้งที่เฉพาะเจาะจงและทั่วไปไม่ใช่วิธีการจัดการพวกเขา
Rotem

@Remem ฉันคิดว่าคุณมีคำตอบที่ดีที่นี่ แต่พีดีเอมีจุด รหัสตามที่เป็นอยู่ทำให้ดูเหมือนจับได้และดำเนินการต่อไปได้ดี ผู้เริ่มต้นบางคนเมื่อเห็นตัวอย่างนี้อาจคิดว่านั่นเป็นวิธีการที่ดี
บ็อบฮอร์น

วางแผนหรือไม่มันทำให้คำตอบของคุณผิด ทันทีที่คุณเริ่มจับข้อยกเว้นเช่น Out Of Memory และ Disk Full แล้วก็กลืนพวกคุณกำลังพิสูจน์ว่าทำไมการจับข้อยกเว้นทั่วไปในความเป็นจริงนั้นไม่ดี
pdr

1
หากคุณตรวจพบข้อยกเว้นทั่วไปเพื่อบันทึกมันคุณควรสร้างใหม่อีกครั้งหลังจากเข้าสู่ระบบ
Victor Hurdugaci

5

ฉันได้ไตร่ตรองอย่างเดียวกันเมื่อเร็ว ๆ นี้และข้อสรุปเบื้องต้นของฉันคือคำถามที่เกิดขึ้นเนื่องจากลำดับชั้นข้อยกเว้นของ. NETนั้นเกิดความสับสนอย่างรุนแรง

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

จากนั้นมี IMNSHO สำคัญเพลี่ยงพล้ำของการมีSEHExceptionการสืบทอดมา (ผ่านExternalException) SystemExceptionจึงทำให้มันเป็น "ปกติ"SystemExceptionเมื่อคุณได้รับSEHExceptionคุณต้องการที่จะเขียนการถ่ายโอนข้อมูลและยุติให้เร็วที่สุดเท่าที่คุณสามารถ - และเริ่มต้นด้วย .NET 4 อย่างน้อยบางส่วนข้อยกเว้น SEH ได้รับการพิจารณาว่าเป็นข้อยกเว้นของรัฐที่เสียหายซึ่งจะไม่ถูกดักจับ สิ่งที่ดีและความจริงที่ทำให้CA1031กฎไร้ประโยชน์มากขึ้นเพราะตอนนี้คนขี้เกียจของคุณcatch (Exception)จะไม่ได้รับสิ่งที่แย่ที่สุดเหล่านี้อยู่ดี

จากนั้นดูเหมือนว่าสิ่งอื่น ๆ ของ Framework จะค่อนข้างไม่สอดคล้องกันทั้งExceptionทางตรงและทางผ่านSystemExceptionทำให้มีความพยายามในการจัดกลุ่มคำสั่งย่อยโดยบางสิ่งบางอย่างเช่นความรุนแรงที่สงสัย

มีชิ้นส่วนโดย Mr. Lippert ที่C#มีชื่อเสียงเรียกว่าVexing Exceptionซึ่งเขาวางหมวดหมู่ของข้อยกเว้นที่มีประโยชน์บางอย่าง: คุณสามารถโต้แย้งว่าคุณต้องการเพียงแค่จับ "exogenous" ยกเว้น ... C#ภาษาและการออกแบบของ. NET ข้อยกเว้นของกรอบทำให้ไม่สามารถ "จับเฉพาะสิ่งภายนอก" ในลักษณะรัดกุม (และเช่นการOutOfMemoryExceptionอาจได้เป็นอย่างดีจะเป็นข้อผิดพลาดที่สามารถกู้คืนได้ทั้งหมดตามปกติสำหรับ API ที่มีการจัดสรรบัฟเฟอร์ที่มีขนาดใหญ่อย่างใด)

บรรทัดล่างสำหรับผมคือว่าวิธีการC#จับบล็อกการทำงานและวิธีการลำดับชั้นยกเว้นกรอบการออกแบบกฎCA1031อยู่นอกเหนือไร้ประโยชน์โดยสิ้นเชิง มันอ้างว่าเพื่อช่วยให้มีปัญหารากของ "ไม่กลืนข้อยกเว้น" แต่กลืนข้อยกเว้นมีศูนย์จะทำอย่างไรกับสิ่งที่คุณจับ แต่กับสิ่งที่คุณแล้วทำ:

มีอย่างน้อย 4 วิธีในการจัดการกับการจับที่ถูกกฎหมายExceptionและCA1031ดูเหมือนว่าจะจัดการกับพวกเขาเพียงคนเดียวเท่านั้น (นั่นคือกรณีการโยนอีกครั้ง)


ตามบันทึกข้างมี C # 6 คุณลักษณะที่เรียกว่ากรองข้อยกเว้นที่จะทำให้เล็กน้อยที่ถูกต้องมากขึ้นอีกครั้งตั้งแต่นั้นมาคุณจะสามารถที่จะถูกต้องอย่างถูกต้องถูกต้องกรองข้อยกเว้นที่คุณต้องการที่จะจับและมีเหตุผลน้อยที่จะเขียนไม่ได้กรองCA1031catch (Exception)


1
ปัญหาที่สำคัญOutOfMemoryExceptionคือไม่มีรหัสวิธีที่ดีที่จะตรวจสอบให้แน่ใจว่ามัน "เท่านั้น" บ่งบอกถึงความล้มเหลวของการจัดสรรโดยเฉพาะอย่างยิ่งหนึ่งได้เตรียมที่จะล้มเหลว เป็นไปได้ว่ามีการโยนข้อยกเว้นที่ร้ายแรงอื่น ๆ และOutOfMemoryExceptionเกิดขึ้นระหว่างการคลายสแต็กจากข้อยกเว้นอื่น Java อาจช้าไปงานปาร์ตี้ด้วย "ลองกับทรัพยากร" แต่มันจัดการข้อยกเว้นในระหว่างการกองคลี่คลายคลี่คลายบิตดีกว่า. NET
supercat

1
@supercat - จริงเพียงพอ แต่มันก็ค่อนข้างจริงสำหรับข้อยกเว้นของระบบทั่วไปอื่น ๆ เมื่อสิ่งที่ไม่ดีในการบล็อกในที่สุด
Martin Ba

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

4

การจัดการข้อยกเว้นโปเกมอน (ต้องจับเลย!) ไม่เลวเสมอไป เมื่อคุณเปิดเผยวิธีการให้กับลูกค้าโดยเฉพาะผู้ใช้มักจะดีกว่าที่จะจับอะไรและทุกอย่างแทนที่จะมีแอปพลิเคชันของคุณพังและเบิร์น

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

ดูที่คำตอบ SO นี้สำหรับการอ่านเพิ่มเติม


1
สถานการณ์นี้ (เมื่อนักพัฒนาจะต้องเป็นผู้ฝึกอบรมโปเกมอน) จะปรากฏขึ้นเมื่อคุณสร้างซอฟต์แวร์ทั้งหมดด้วยตัวคุณเอง: คุณสร้างเลเยอร์การเชื่อมต่อฐานข้อมูลและ GUI ของผู้ใช้ แอปของคุณต้องกู้คืนจากสถานการณ์เช่นการเชื่อมต่อขาดหายลบโฟลเดอร์ของผู้ใช้ข้อมูลเสียหาย ฯลฯ ผู้ใช้ปลายทางไม่ชอบแอปที่ขัดข้องและเบิร์น พวกเขาชอบแอพที่สามารถใช้งานได้บนคอมพิวเตอร์ที่กำลังระเบิดซึ่งกำลังระเบิด!
Broken_Window

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

2
@Magus: ด้วยวิธีการเช่นLoadDocument()นี้เป็นไปไม่ได้ที่จะระบุทุกสิ่งที่อาจผิดพลาด แต่ 99% ของข้อยกเว้นที่อาจถูกโยนได้ก็หมายถึง "มันเป็นไปไม่ได้ที่จะตีความเนื้อหาของไฟล์ด้วยชื่อที่กำหนด เอกสารจัดการกับมัน " หากมีคนพยายามเปิดบางสิ่งที่ไม่ใช่ไฟล์เอกสารที่ถูกต้องแสดงว่าไม่ควรทำให้แอปพลิเคชันเสียหายและฆ่าเอกสารที่เปิดอยู่อื่น ๆ การจัดการข้อผิดพลาดของโปเกมอนในกรณีเช่นนี้น่าเกลียด แต่ฉันไม่รู้ทางเลือกที่ดีเลย
supercat

@supercat: ฉันเพิ่งทำประเด็นทางภาษา อย่างไรก็ตามฉันไม่คิดว่าเนื้อหาไฟล์ที่ไม่ถูกต้องดูเหมือนสิ่งที่ควรมีข้อยกเว้นมากกว่าหนึ่งประเภท
Magus

1
@Magus: มันสามารถโยนข้อยกเว้นได้ทุกประเภท - นั่นคือปัญหา มักเป็นเรื่องยากมากที่จะคาดการณ์ข้อยกเว้นทุกประเภทที่อาจเกิดขึ้นเนื่องจากข้อมูลที่ไม่ถูกต้องในไฟล์ หากไม่มีการจัดการ PokeMon ความเสี่ยงหนึ่งที่ทำให้แอปพลิเคชันตายเพราะเช่นไฟล์ที่โหลดมีสตริงที่มีความยาวเป็นพิเศษในสถานที่ซึ่งต้องใช้จำนวนเต็ม 32 บิตในรูปแบบทศนิยมและมีตัวเลขล้นใน ตรรกะการแยกวิเคราะห์
supercat

1

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

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

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


0

ฉันเข้าใจเหตุผลของกฎนี้ แต่ในทางปฏิบัติถ้าฉันต้องการที่จะทำสิ่งเดียวกันโดยไม่คำนึงถึงข้อยกเว้นที่ถูกโยนออกไปทำไมฉันต้องจัดการแต่ละอย่างโดยเฉพาะ?

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

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

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

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

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

ดังนั้นถ้าฉันต้องการละเว้นข้อยกเว้นทุกอย่างยกเว้น OutOfMemoryException

IMHO นี่เป็นวิธีที่ผิดที่จะคิดเกี่ยวกับการจัดการข้อยกเว้น คุณควรดำเนินการกับบัญชีขาว (ตรวจจับประเภท A และ B) ไม่ใช่บัญชีดำ (ยกเว้นทุกข้อยกเว้นนอกเหนือจาก X)


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

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

0

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

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

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

คุณไม่ต้องการรับการแจ้งเตือนทันทีว่ามีปัญหานี้หรือไม่ดังนั้นคุณสามารถแก้ไขได้ การกลืนข้อยกเว้นหมายความว่าคุณไม่เคยรู้ว่ามีบางอย่างผิดปกติ

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


0

ฉันต้องการพูดถึงเรื่องนี้จากมุมมองเชิงตรรกะมากกว่ามุมมองเชิงเทคนิค

ตอนนี้ฉันต้องเปลี่ยนรหัสเพื่อจัดการข้อยกเว้นใหม่นั้น

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

คำถามของคุณก็คือ "ถ้าฉันไม่สนใจสิ่งที่ผิดพลาดฉันต้องผ่านความยุ่งยากในการค้นหาว่ามันคืออะไรหรือไม่"

นี่คือส่วนความงาม: ไม่คุณไม่ได้ทำ

"ดังนั้นฉันสามารถดูวิธีอื่นและมีสิ่งที่น่ารังเกียจปรากฏขึ้นกวาดใต้พรมโดยอัตโนมัติและทำได้ด้วยหรือไม่"

ไม่นั่นไม่ใช่วิธีการทำงานเช่นกัน

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

"แต่ ... แต่ ... แล้วถ้าอย่างนั้นข้อยกเว้นอย่างอื่นที่ฉันไม่สนใจอาจทำให้งานของฉันล้มเหลว!"

ใช่. แต่พวกเขาจะมีความสำคัญมากกว่าคนที่จัดการในพื้นที่เสมอ เหมือนสัญญาณเตือนไฟไหม้หรือหัวหน้าบอกให้คุณหยุดสิ่งที่คุณกำลังทำและรับภารกิจเร่งด่วนที่โผล่ขึ้นมา


-3

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

คุณไม่ควรรับข้อยกเว้นทั่วไปและพยายามดำเนินการต่อ

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