แนวทางปฏิบัติที่ดีที่สุดสำหรับการจัดการข้อยกเว้นใน Java หรือ C # [ปิด]


117

ฉันกำลังตัดสินใจว่าจะจัดการข้อยกเว้นในแอปพลิเคชันของฉันอย่างไร

มากถ้าปัญหาของฉันเกี่ยวกับข้อยกเว้นมาจาก 1) การเข้าถึงข้อมูลผ่านบริการระยะไกลหรือ 2) การยกเลิกการกำหนดค่าออบเจ็กต์ JSON น่าเสียดายที่ฉันไม่สามารถรับประกันความสำเร็จสำหรับงานเหล่านี้ได้ (ตัดการเชื่อมต่อเครือข่ายอ็อบเจ็กต์ JSON ที่ผิดรูปแบบซึ่งไม่สามารถควบคุมได้)

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

นี่คือตัวอย่างโค้ดบางส่วน (ใน JAVA) ของวิธีการทั่วไป)

public boolean doSomething(Object p_somthingToDoOn)
{
    boolean result = false;

    try{
        // if dirty object then clean
        doactualStuffOnObject(p_jsonObject);

        //assume success (no exception thrown)
        result = true;
    }
    catch(Exception Ex)
    {
        //don't care about exceptions
        Ex.printStackTrace();
    }
    return result;
}

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

โดยสรุปคำถามสำคัญ:

  1. เป็นเรื่องปกติหรือไม่ที่จะจับข้อยกเว้น แต่ไม่ทำให้เกิดฟองหรือแจ้งระบบอย่างเป็นทางการ (ผ่านบันทึกหรือการแจ้งเตือนไปยังผู้ใช้)
  2. มีแนวทางปฏิบัติที่ดีที่สุดอะไรบ้างสำหรับข้อยกเว้นที่ไม่ส่งผลให้ทุกอย่างต้องมีการบล็อก try / catch

ติดตาม / แก้ไข

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

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

นอกจากนี้ระวังรหัสเน่าผ่านการลอง / จับมากเกินไปหรือไม่ให้ข้อยกเว้นด้วยความเคารพ (ข้อยกเว้นคือเตือนระบบต้องเตือนอะไรอีกบ้าง)

นอกจากนี้เป็นความคิดเห็นทางเลือกสวยจากm3rLinEz

ฉันมักจะเห็นด้วยกับ Anders Hejlsberg และคุณว่าผู้โทรส่วนใหญ่สนใจว่าการดำเนินการจะประสบความสำเร็จหรือไม่เท่านั้น

จากความคิดเห็นนี้จะทำให้เกิดคำถามที่ควรคำนึงถึงเมื่อจัดการกับข้อยกเว้น:

  • อะไรคือจุดที่มีการโยนข้อยกเว้นนี้?
  • มันสมเหตุสมผลอย่างไรที่จะจัดการกับมัน?
  • ผู้โทรสนใจเกี่ยวกับข้อยกเว้นจริง ๆ หรือเพียงแค่สนใจว่าการโทรสำเร็จหรือไม่?
  • กำลังบังคับให้ผู้โทรจัดการข้อยกเว้นที่อาจเกิดขึ้นอย่างสง่างามหรือไม่?
  • คุณเคารพในสำนวนของภาษาหรือไม่?
    • คุณจำเป็นต้องคืนค่าสถานะความสำเร็จเช่นบูลีนหรือไม่? การคืนค่าบูลีน (หรือ int) เป็นชุดความคิด C มากกว่า Java (ใน Java คุณจะจัดการกับข้อยกเว้น)
    • ทำตามโครงสร้างการจัดการข้อผิดพลาดที่เกี่ยวข้องกับภาษา :)!

แม้ว่าบทความจากชุมชน oracle จะอยู่ใน java แต่ก็เป็นคำแนะนำทั่วไปสำหรับภาษาที่ค่อนข้างกว้าง บทความดีสิ่งที่ฉันกำลังมองหา
Bunny Rabbit

คำตอบ:


61

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

สำหรับคำถามของคุณ:

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

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

สิ่งที่ดีที่สุดที่คุณสามารถทำได้คือห่อรหัสข้อผิดพลาดของคุณใน monad
lindenrovio

@Trejkaz คุณไม่ต้องการส่งคืนรายละเอียดข้อยกเว้นให้กับผู้ใช้เพราะนั่นเป็นความเสี่ยงด้านความปลอดภัย นี่คือสาเหตุที่เซิร์ฟเวอร์ HTML ส่งคืนรหัสข้อผิดพลาด นอกจากนี้ยังเป็นปัญหาในการแปลเพื่อส่งคืนข้อความแสดงข้อผิดพลาดและอาจทำให้ HTML มีขนาดใหญ่ขึ้นและส่งคืนได้ช้าลง ทั้งหมดนี้คือเหตุผลที่ฉันคิดว่าเซิร์ฟเวอร์ HTML ส่งคืนรหัสข้อผิดพลาด
Didier A.

ฉันคิดว่าดีกว่าที่จะพูดว่า: "คุณควรยกเลิกเฉพาะข้อยกเว้นที่คุณสามารถจัดการได้จริง"
Didier A.

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

25

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

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

โดยทั่วไปฉันใช้กฎต่อไปนี้:

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

ฉันพบว่ารหัสต่อไปนี้เป็นกลิ่น:

try
{
    //do something
}
catch(Exception)
{
   throw;
}

รหัสเช่นนี้ไม่มีจุดและไม่ควรรวมอยู่ด้วย


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

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

รหัสทำหน้าที่จุด: คุณสามารถกำหนดจุดพักที่ "โยน"
Rauhotz

3
จุดอ่อนคุณสามารถบอกให้ VS ทำลายข้อยกเว้นใด ๆ หรือคุณสามารถ จำกัด ขอบเขตให้แคบลงและเลือกข้อยกเว้นเฉพาะ ใน VS2008 มีรายการเมนูอยู่ภายใต้การดีบัก (คุณต้องปรับแต่งแถบเครื่องมือของคุณเพื่อค้นหา) เรียกว่าข้อยกเว้น
JoshBerke

ตัวอย่าง "กลิ่นรหัส" มีผลข้างเคียงที่ชัดเจนแม้ในรูปแบบธรรมดานั้น หาก// do somethingมีtry/finallyบล็อกใด ๆรอบจุดที่ขว้างfinallyบล็อกจะดำเนินการก่อนcatchบล็อก หากไม่มีtry/catchข้อยกเว้นจะบินขึ้นไปด้านบนสุดของสแต็กโดยไม่มีการfinallyบล็อกใด ๆ สิ่งนี้ช่วยให้ตัวจัดการระดับบนสุดสามารถตัดสินใจได้ว่าจะดำเนินการfinallyบล็อกหรือไม่
Daniel Earwicker

9

ฉันขอแนะนำแหล่งข้อมูลดีๆอีกแห่งในหัวข้อ เป็นการสัมภาษณ์ผู้ประดิษฐ์ C # และ Java, Anders Hejlsberg และ James Gosling ตามลำดับในหัวข้อ Checked Exception ของ Java

ความล้มเหลวและข้อยกเว้น

นอกจากนี้ยังมีแหล่งข้อมูลที่ยอดเยี่ยมที่ด้านล่างของหน้า

ฉันมักจะเห็นด้วยกับ Anders Hejlsberg และคุณว่าผู้โทรส่วนใหญ่สนใจว่าการดำเนินการจะประสบความสำเร็จหรือไม่เท่านั้น

Bill Venners : คุณได้กล่าวถึงความสามารถในการปรับขนาดและการกำหนดเวอร์ชันที่เกี่ยวข้องกับข้อยกเว้นที่ตรวจสอบแล้ว คุณช่วยชี้แจงความหมายของทั้งสองประเด็นได้หรือไม่?

Anders Hejlsberg : เรามาเริ่มกันที่การกำหนดเวอร์ชันกันดีกว่าเพราะปัญหานั้นค่อนข้างง่ายที่จะเห็นที่นั่น สมมติว่าฉันสร้างเมธอด foo ที่ประกาศว่ามันโยนข้อยกเว้น A, B และ C ในเวอร์ชันที่สองของ foo ฉันต้องการเพิ่มคุณสมบัติมากมายและตอนนี้ foo อาจทำให้เกิดข้อยกเว้น D มันเป็นการเปลี่ยนแปลงที่ผิดปกติสำหรับฉันที่จะ เพิ่ม D ในส่วนคำสั่งพ่นของเมธอดนั้นเนื่องจากผู้เรียกที่มีอยู่ของเมธอดนั้นแทบจะไม่จัดการกับข้อยกเว้นนั้น

การเพิ่มข้อยกเว้นใหม่ให้กับ throws clause ในเวอร์ชันใหม่จะทำให้โค้ดไคลเอ็นต์แตก มันเหมือนกับการเพิ่มวิธีการในอินเทอร์เฟซ หลังจากที่คุณเผยแพร่อินเทอร์เฟซมันมีไว้สำหรับวัตถุประสงค์ในทางปฏิบัติทั้งหมดที่ไม่เปลี่ยนรูปเนื่องจากการนำไปใช้งานใด ๆ อาจมีวิธีการที่คุณต้องการเพิ่มในเวอร์ชันถัดไป คุณต้องสร้างอินเทอร์เฟซใหม่แทน ในทำนองเดียวกันกับข้อยกเว้นคุณอาจต้องสร้างวิธีการใหม่ทั้งหมดที่เรียกว่า foo2 ซึ่งจะทำให้เกิดข้อยกเว้นมากขึ้นหรือคุณจะต้องจับข้อยกเว้น D ใน foo ใหม่และแปลง D เป็น A, B หรือ C

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

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

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

แก้ไข: เพิ่มรายละเอียดเพิ่มเติมเกี่ยวกับคอนเวอร์สเตชั่น


ขอบคุณสำหรับสิ่งนี้! ฉันอัปเดตคำถามของฉันพร้อมข้อมูลเกี่ยวกับคำตอบของคุณ!
AtariPete

ดูเหมือนว่า Mr. Hejlsberg กำลังให้เหตุผลในการจัดการข้อยกเว้นโปเกมอน ปัญหาใหญ่อย่างหนึ่งในการออกแบบข้อยกเว้นใน Java และ C # คือการเข้ารหัสข้อมูลมากเกินไปในประเภทของข้อยกเว้นในขณะที่ข้อมูลควรถูกเก็บไว้ในกรณียกเว้นไม่สามารถใช้ได้ในลักษณะที่สอดคล้องกัน ข้อยกเว้นควรแพร่กระจายไปยัง call stack จนกว่าเงื่อนไขผิดปกติทั้งหมดที่แสดงจึงได้รับการแก้ไข น่าเสียดายที่ประเภทของข้อยกเว้น - แม้ว่าจะได้รับการยอมรับ - เพียงเล็กน้อยเพื่อบ่งชี้ว่าสถานการณ์ได้รับการแก้ไขหรือไม่ หากไม่รู้จักข้อยกเว้น ...
supercat

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

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

8

ข้อยกเว้นที่ตรวจสอบแล้วเป็นปัญหาที่ถกเถียงกันโดยทั่วไปและโดยเฉพาะใน Java (ในภายหลังฉันจะพยายามหาตัวอย่างสำหรับผู้ที่เห็นด้วยและไม่เห็นด้วย)

ตามกฎทั่วไปการจัดการข้อยกเว้นควรเป็นสิ่งที่อยู่รอบ ๆ หลักเกณฑ์เหล่านี้โดยไม่เรียงตามลำดับ:

  • เพื่อประโยชน์ในการบำรุงรักษาให้บันทึกข้อยกเว้นไว้เสมอเพื่อที่เมื่อคุณเริ่มเห็นจุดบกพร่องบันทึกจะช่วยชี้คุณไปยังจุดที่จุดบกพร่องของคุณน่าจะเริ่มต้นขึ้น อย่าปล่อยทิ้งไว้printStackTrace()หรือชอบมันมีโอกาสที่ผู้ใช้ของคุณจะได้รับสแต็กเทรซอย่างใดอย่างหนึ่งในที่สุดและไม่มีความรู้เลยว่าจะทำอย่างไรกับมัน
  • จับข้อยกเว้นที่คุณสามารถจัดการได้และมีเพียงข้อยกเว้นเหล่านั้นและจัดการได้อย่าเพิ่งโยนมันขึ้นมากอง
  • จับระดับข้อยกเว้นที่เฉพาะเจาะจงเสมอและโดยทั่วไปคุณไม่ควรจับประเภทExceptionคุณมีแนวโน้มที่จะกลืนข้อยกเว้นที่สำคัญเป็นอย่างอื่น
  • ไม่เคย (เคย) จับError!! , ความหมาย: อย่าจับThrowablesเป็นErrors เป็นคลาสย่อยของหลัง Errorเป็นปัญหาที่คุณมักจะไม่สามารถจัดการได้ (เช่นOutOfMemoryหรือปัญหา JVM อื่น ๆ )

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


ข้อยกเว้นที่ตรวจสอบแล้วไม่ใช่ปัญหาใน C # เพราะไม่มี
cletus

3
Imho บางครั้งมันก็ดีที่จะจับข้อผิดพลาด: ฉันจำแอพ Java ที่ใช้หน่วยความจำมากที่ฉันเขียน ฉันจับ OutOfMemory-Ex และแสดงข้อความให้ผู้ใช้ทราบว่าเขามีหน่วยความจำไม่เพียงพอเขาควรออกจากโปรแกรมอื่นและบอกวิธีเริ่มต้น jvm โดยมีการกำหนดพื้นที่ฮีปให้มากขึ้น ฉันเดาว่ามันช่วยได้
Lena Schimmel

5

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


3

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

อดีต

try
{
   sendMessage();

   if(message == success)
   {
       doStuff();
   }
   else if(message == failed)
   {
       throw;
   }
}
catch(Exception)
{
    logAndRecover();
}

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


2

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

เราตกลงกันว่าSystemExceptionไม่น่าจะกู้คืนได้และจะจัดการครั้งเดียวที่ด้านบน เพื่อให้บริบทเพิ่มเติมของเราSystemExceptions จะ exteneded เพื่อระบุตำแหน่งที่พวกเขาเกิดขึ้นเช่นRepositoryException, ServiceEceptionฯลฯ

ApplicationExceptions อาจมีความหมายทางธุรกิจเช่นInsufficientFundsExceptionและควรได้รับการจัดการโดยรหัสลูกค้า

Witohut เป็นตัวอย่างที่เป็นรูปธรรมการแสดงความคิดเห็นเกี่ยวกับการใช้งานของคุณทำได้ยาก แต่ฉันจะไม่ใช้รหัสส่งคืนเนื่องจากเป็นปัญหาในการบำรุงรักษา คุณอาจกลืน Exception แต่คุณต้องตัดสินใจว่าเหตุใดและบันทึกเหตุการณ์และ stacktrace เสมอ สุดท้ายเนื่องจากวิธีการของคุณไม่มีการประมวลผลอื่นจึงค่อนข้างซ้ำซ้อน (ยกเว้นการห่อหุ้ม?) ดังนั้นจึงdoactualStuffOnObject(p_jsonObject);สามารถคืนค่าบูลีนได้!


1

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

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

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


1

หากคุณกำลังจะใช้รูปแบบโค้ดในตัวอย่างของคุณให้เรียกมันว่า TryDoSomething และจับเฉพาะข้อยกเว้นเฉพาะ

ลองใช้ตัวกรองข้อยกเว้นด้วยเมื่อเข้าสู่ระบบข้อยกเว้นสำหรับวัตถุประสงค์ในการวินิจฉัย VB รองรับภาษาสำหรับตัวกรองข้อยกเว้น ลิงก์ไปยังบล็อกของ Greggm มีการใช้งานที่สามารถใช้ได้จาก C # ตัวกรองข้อยกเว้นมีคุณสมบัติที่ดีกว่าสำหรับความสามารถในการดีบั๊กเหนือการดักจับและการปลูกใหม่ โดยเฉพาะคุณสามารถบันทึกปัญหาในตัวกรองและปล่อยให้ข้อยกเว้นเผยแพร่ต่อไป วิธีนี้ช่วยให้การติดดีบักเกอร์ JIT (Just in Time) มีสแต็กดั้งเดิมเต็มรูปแบบ การปลูกซ้ำจะตัดสแต็กออกเมื่อถึงจุดที่ถูกปลูกใหม่

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

// throws NumberNotHexidecimalException
int ParseHexidecimal(string numberToParse); 

bool TryParseHexidecimal(string numberToParse, out int parsedInt)
{
     try
     {
         parsedInt = ParseHexidecimal(numberToParse);
         return true;
     }
     catch(NumberNotHexidecimalException ex)
     {
         parsedInt = 0;
         return false;
     }
     catch(Exception ex)
     {
         // Implement the error policy for unexpected exceptions:
         // log a callstack, assert if a debugger is attached etc.
         LogRetailAssert(ex);
         // rethrow the exception
         // The downside is that a JIT debugger will have the next
         // line as the place that threw the exception, rather than
         // the original location further down the stack.
         throw;
         // A better practice is to use an exception filter here.
         // see the link to Exception Filter Inject above
         // http://code.msdn.microsoft.com/ExceptionFilterInjct
     }
}

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


ฉันชอบรูปแบบ TryXXX ใน. net
JoshBerke

1

ฉันขอแนะนำให้ใช้ตัวชี้นำของคุณจากไลบรารีมาตรฐานสำหรับภาษาที่คุณใช้ ฉันพูดภาษา C # ไม่ได้ แต่ลองดูที่ Java

ตัวอย่างเช่น java.lang.reflect.Array มีsetวิธีการแบบคงที่:

static void set(Object array, int index, Object value);

ทาง C จะเป็น

static int set(Object array, int index, Object value);

... โดยมีมูลค่าคืนเป็นตัวบ่งชี้ความสำเร็จ แต่คุณไม่ได้อยู่ในโลก C อีกต่อไป

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

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


นี่เป็นความคิดเห็นที่ถูกต้องมากควรเคารพภาษาและวิธีจัดการปัญหาดังกล่าวตามเนื้อผ้า อย่านำ C mindset มาสู่โลก Java
AtariPete

0

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

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

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


อย่าลืมว่าการตั้งค่าบล็อกข้อยกเว้นก็มีค่าใช้จ่ายเช่นกัน ...
devstuff

0

กลยุทธ์ของฉัน:

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

หากฟังก์ชันควรส่งคืนบางสิ่งเมื่อเกิดข้อยกเว้น / ข้อผิดพลาดให้คืนค่า nullมิฉะนั้นรายการที่ส่งคืนได้

แทนที่จะเป็นบูลสตริงอาจจะกลับมามีรายละเอียดของข้อผิดพลาด

ในทุกกรณีก่อนที่จะส่งคืนสิ่งใดให้บันทึกข้อผิดพลาด


0

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


ฉันเห็นด้วยอย่างยิ่ง ฉันทำ Ex.printStackTrace () เท่านั้น เป็นตัวอย่างของสิ่งที่ฉันทำในการจับ (เช่นไม่ปลูกใหม่)
AtariPete

0

บล็อก try / catch เป็นตรรกะชุดที่สองที่ฝังอยู่ในชุดแรก (หลัก) ดังนั้นจึงเป็นวิธีที่ดีในการทุบรหัสสปาเก็ตตี้ที่ไม่สามารถอ่านได้ยากที่จะแก้ไขข้อบกพร่อง

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

  • ใช้ (เท่าที่จำเป็น) ในระดับต่ำเพื่อตรวจจับปัญหาการจัดการไลบรารีและสตรีมกลับไปยังโฟลว์ตรรกะหลัก การจัดการข้อผิดพลาดส่วนใหญ่ที่เราต้องการควรมาจากโค้ดเองซึ่งเป็นส่วนหนึ่งของข้อมูลเอง ทำไมต้องสร้างเงื่อนไขพิเศษหากข้อมูลที่ส่งคืนไม่พิเศษ

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

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

พอล


0

ฉันอาจจะตอบช้าไปหน่อย แต่การจัดการข้อผิดพลาดเป็นสิ่งที่เราสามารถเปลี่ยนแปลงและพัฒนาได้ตลอดเวลา หากคุณต้องการอ่านข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ฉันเขียนโพสต์ในบล็อกใหม่ของฉันเกี่ยวกับเรื่องนี้http://taoofdevelopment.wordpress.com

มีความสุขในการเขียนโค้ด

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