ควรโยนข้อยกเว้นเมื่อใด


435

ฉันมีข้อยกเว้นที่สร้างขึ้นสำหรับทุกเงื่อนไขที่ใบสมัครของฉันไม่ได้คาดไว้ UserNameNotValidException, PasswordNotCorrectExceptionฯลฯ

อย่างไรก็ตามฉันถูกบอกว่าฉันไม่ควรสร้างข้อยกเว้นสำหรับเงื่อนไขเหล่านั้น ใน UML ของฉันมีข้อยกเว้นสำหรับโฟลว์หลักดังนั้นทำไมมันไม่ควรเป็นข้อยกเว้น?

คำแนะนำหรือแนวทางปฏิบัติที่ดีที่สุดสำหรับการสร้างข้อยกเว้น?


58
โปรดเปิดใหม่อีกครั้งนี่เป็นคำถามที่สมเหตุสมผลและสมเหตุสมผล คำถามใด ๆ เกี่ยวข้องกับความเห็นจำนวนหนึ่ง แต่ในกรณีนี้ฉันสงสัยว่ามันเป็นเรื่องของ 'วิธีปฏิบัติที่ดีที่สุด'
Tim Long

19
+1 สำหรับเปิดใหม่ หัวข้อที่น่าสนใจอื่น ๆ อีกมากมาย 'ขึ้นอยู่กับ' และเป็นประโยชน์อย่างมากในการวิเคราะห์การแลกเปลี่ยนเมื่อตัดสินใจ ความจริงที่ว่าผู้คนสับสนความคิดเห็นกับข้อเท็จจริงในคำตอบไม่ได้คัดค้านนี้ การลอดผ่านโคลนเป็นการออกกำลังกายที่ควรปล่อยให้ผู้อ่านอ่าน
Aron

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

6
Microsoft กล่าวว่า: "อย่าส่งคืนรหัสข้อผิดพลาดข้อยกเว้นเป็นวิธีหลักในการรายงานข้อผิดพลาดในกรอบงาน" และ "... หากสมาชิกไม่สามารถทำสิ่งที่ออกแบบมาให้สำเร็จได้ควรถือว่าการดำเนินการล้มเหลวและมีการโยนข้อยกเว้น" msdn.microsoft.com/library/ms229030%28v=vs.100%29.aspx
Matsen75

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

คำตอบ:


629

แนวทางส่วนบุคคลของฉันคือ: ข้อยกเว้นจะถูกโยนทิ้งเมื่อพบว่ามีการสันนิษฐานเบื้องต้นของบล็อกโค้ดปัจจุบันว่าเป็นเท็จ

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

ตัวอย่างที่ 2: พูดว่าฉันมีฟังก์ชั่นอื่นซึ่งตรวจสอบรายการ <> และส่งกลับค่าจริงถ้าความยาวของมันมากกว่า 50 และเท็จถ้าความยาวน้อยกว่า ฟังก์ชันนี้ถามคำถามว่า "รายการนี้มีมากกว่า 50 รายการหรือไม่" แต่คำถามนี้ทำให้สมมติฐาน - มันถือว่าสมมติว่าวัตถุที่ได้รับคือรายการ ถ้าฉันส่งมันเป็น NULL ข้อสันนิษฐานนั้นจะเป็นเท็จ ในกรณีนั้นถ้าฟังก์ชั่นส่งกลับทั้งจริงหรือเท็จก็จะทำลายกฎของตัวเอง ฟังก์ชั่นไม่สามารถคืนสิ่งใด ๆและอ้างว่าตอบคำถามได้อย่างถูกต้อง ดังนั้นมันจึงไม่กลับมา - มันส่งข้อยกเว้น

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

อีกด้านหนึ่งของสมการนี้คือ: หากคุณพบว่าฟังก์ชันของคุณมีการโยนข้อยกเว้นบ่อยครั้งคุณอาจต้องปรับแต่งสมมติฐานของพวกเขา


15
แน่นอน! ข้อยกเว้นจะถูกโยนเมื่อใดก็ต่อเมื่อเงื่อนไขเบื้องต้นของฟังก์ชั่น (สมมติฐานเกี่ยวกับข้อโต้แย้ง) แตก !
Lightman

11
ในภาษาศาสตร์บางครั้งเรียกว่าความล้มเหลวก่อนเวลาอันควร ตัวอย่างคลาสสิกเกิดจากเบอร์ทรานด์รัสเซิล: "Is the King of France bald" ไม่สามารถตอบได้ว่าใช่หรือไม่ใช่ (การตอบสนอง "ราชาแห่งฝรั่งเศสนั้นศีรษะล้าน" ไม่จริงหรือเท็จ) เพราะมันมีการสันนิษฐานผิด ๆ นั่นคือมีกษัตริย์ของฝรั่งเศส ความล้มเหลวก่อนการอนุมานมักจะพบได้พร้อมคำอธิบายที่ชัดเจนและเป็นเรื่องปกติเมื่อเขียนโปรแกรม เช่น "ส่วนหัวของรายการ" มีความล้มเหลวก่อนเมื่อรายการว่างเปล่าและจากนั้นจึงเหมาะสมที่จะส่งข้อยกเว้น
Mohan

นี่อาจเป็นคำอธิบายที่ดีที่สุด!
gaurav

ขอบคุณ. ดังนั้น. มาก. "คือราชาแห่งฝรั่งเศสหัวโล้น" ฉันเคยได้ยินเรื่องนี้มาก่อนในการค้นคว้าป่าของ meinong .... :) ขอบคุณ @Mohan
ErlichBachman

285

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


3
อืมไม่มี ข้อยกเว้นสามารถใช้เป็นกลไกการควบคุมการไหลหากไม่ต้องการประสิทธิภาพสูงสุดซึ่งเป็นจริงสำหรับเว็บแอพส่วนใหญ่ Python ใช้ข้อยกเว้น 'StopIteration' เพื่อยกเลิกตัววนซ้ำและทำงานได้ดีมาก ค่าใช้จ่ายไม่มีอะไรเทียบกับ IO และอื่น ๆ
Seun Osewa

9
+1 คำตอบที่ดี ฉันรู้สึกหงุดหงิดอย่างมากจากนักพัฒนาที่ทำงานบน API ที่ฉันต้องใช้และโยนข้อยกเว้นสำหรับทุกสิ่งเล็กน้อย บางกรณีจำเป็นต้องมีข้อยกเว้นจริงๆ หากคุณมีข้อยกเว้นที่แตกต่างกัน 25 แบบให้ดูที่การออกแบบของคุณอีกครั้งคุณอาจทำผิดพลาด
7wp

1
ควรมีข้อยกเว้นเมื่อผู้ใช้พยายามดำเนินการที่ผิดกฎหมายซึ่งไม่ได้รับอนุญาตจากการจัดการโค้ดของหน้าเว็บหรือไม่เช่นการลบโพสต์ของใครบางคนที่นี่ที่ StackOverflow
Rajat Gupta

30
ข้อยกเว้นคือการควบคุมกลไกการไหล คุณสามารถโยนพวกเขา คุณสามารถจับพวกเขา คุณย้ายการควบคุมไปยังรหัสอื่น นั่นคือการควบคุมการไหล เหตุผลเดียวที่ภาษามีข้อยกเว้นคือคุณสามารถเขียนโค้ดได้อย่างตรงไปตรงมาโดยไม่ถามว่า "สิ่งนั้นล้มเหลวหรือไม่" หลังจากทุกสิ่งที่คุณทำ ตัวอย่าง Haskell ไม่มีข้อยกเว้นเนื่องจาก monads และ do-notation สามารถทำการตรวจสอบข้อผิดพลาดได้โดยอัตโนมัติ
เจสซี่

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

67

แนวทางเล็ก ๆ ของฉันได้รับอิทธิพลอย่างมากจากหนังสือ "รหัสสมบูรณ์" ที่ยอดเยี่ยม:

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

35

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

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


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

1
ข้อยกเว้นที่ตรวจสอบมีชุดของปัญหา ฉันยังคงควรใช้ข้อยกเว้นของ "สถานการณ์พิเศษ" ไม่ใช่สำหรับสิ่งที่เป็นส่วนหนึ่งของเวิร์กโฟลว์ปกติ
EricSchaefer

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

1
ควรมีข้อยกเว้นเมื่อผู้ใช้พยายามดำเนินการที่ผิดกฎหมายซึ่งไม่ได้รับอนุญาตจากการจัดการโค้ดของหน้าเว็บหรือไม่เช่นการลบโพสต์ของใครบางคนที่นี่ที่ StackOverflow
Rajat Gupta

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

28

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


6
คุณไม่จำเป็นต้องหยุดการทำงานของโปรแกรมด้วยข้อยกเว้น ... โยนข้อยกเว้นผู้เรียกจะจับ exeption และควรจัดการถ้าเป็นไปได้บันทึกและข้อผิดพลาดและดำเนินการต่อ มันเป็น 'ฟอร์มที่ไม่ดี' เพียงแค่ทำการขว้างข้อยกเว้นให้กับสแต็คการโทร - จับที่มันเกิดขึ้นและจัดการกับมันที่นั่น
Krakkos

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

" ไฟล์ที่หายไปบนดิสก์ " กรอบภาษาส่วนใหญ่เช่น. NET Framework ให้ API เพื่อตรวจสอบการมีอยู่ของไฟล์เช่นกัน ทำไมไม่ใช้พวกเขาก่อนที่จะเข้าถึงไฟล์โดยตรง!
user1451111

23

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

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


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

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

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

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

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

17

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

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


14

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


คุณจะเห็นคำแนะนำมากมายรวมถึงคำตอบสำหรับคำถามนี้ว่าคุณควรโยนข้อยกเว้นเฉพาะในสถานการณ์ "พิเศษ" ดูเหมือนจะสมเหตุสมผลมาก แต่ก็มีคำแนะนำที่สมบูรณ์เพราะมันมาแทนที่คำถามหนึ่งข้อ ("เมื่อใดที่ฉันควรจะยกเว้น") ด้วยคำถามส่วนตัวอีกคำถาม ("อะไรคือสิ่งที่พิเศษ") ให้ทำตามคำแนะนำของ Herb Sutter (สำหรับ C ++ ที่มีอยู่ในบทความ Dr Dobbs เมื่อใดและวิธีการใช้ข้อยกเว้นและในหนังสือของเขากับ Andrei Alexandrescu, มาตรฐานการเข้ารหัส C ++ ): โยนข้อยกเว้นถ้าและเฉพาะในกรณีที่

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

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

  • Preconditions, postconditions และ invariants เป็นลักษณะการออกแบบของโปรแกรมของเรา (API ภายใน) ในขณะที่การตัดสินใจในthrowรายละเอียดการใช้งาน มันบังคับให้เราจำไว้ว่าเราต้องพิจารณาการออกแบบและการนำไปใช้แยกต่างหากและงานของเราในขณะที่ใช้วิธีการคือผลิตบางสิ่งที่ตรงตามข้อ จำกัด ในการออกแบบ
  • มันบังคับให้เราต้องคิดในแง่ของเงื่อนไขก่อนหลังเงื่อนไขและค่าคงที่ซึ่งเป็นเพียงสมมติฐานเดียวที่ผู้เรียกวิธีการของเราควรทำ
  • การมีเพศสัมพันธ์แบบหลวมนั้นช่วยให้เราสามารถปรับโครงสร้างการใช้งานได้ถ้าจำเป็น
  • โพสต์เงื่อนไขและค่าคงที่ทดสอบได้; มันส่งผลให้ในรหัสที่สามารถทดสอบหน่วยได้ง่ายเพราะโพสต์เงื่อนไขเป็นภาคที่รหัสการทดสอบหน่วยของเราสามารถตรวจสอบ (ยืนยัน)
  • การคิดในแง่ของการโพสต์เงื่อนไขเป็นธรรมชาติสร้างการออกแบบที่มีความสำเร็จเป็นโพสต์เงื่อนไขซึ่งเป็นสไตล์ธรรมชาติสำหรับการใช้ข้อยกเว้น เส้นทางการดำเนินการปกติ ("แฮปปี้") ของโปรแกรมของคุณวางแบบเป็นเส้นตรงโดยมีรหัสการจัดการข้อผิดพลาดทั้งหมดถูกย้ายไปยังส่วนcatchคำสั่ง

10

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

เหตุผลในการใช้ข้อยกเว้น:

  • โฟลว์โค้ดสำหรับเคสทั่วไปนั้นชัดเจนขึ้น
  • สามารถส่งคืนข้อมูลข้อผิดพลาดที่ซับซ้อนเป็นวัตถุ (แม้ว่าจะสามารถทำได้โดยใช้ข้อผิดพลาด "ออก" พารามิเตอร์ผ่านการอ้างอิง)
  • โดยทั่วไปภาษาจะให้ความสะดวกในการจัดการการล้างข้อมูลที่เป็นระเบียบในกรณีที่มีข้อยกเว้น (ลอง / สุดท้ายใน Java โดยใช้ใน C #, RAII ใน C ++)
  • ในกรณีที่ไม่มีข้อยกเว้นบางครั้งการดำเนินการอาจเร็วกว่าการตรวจสอบรหัสส่งคืน
  • ใน Java ต้องมีการประกาศหรือตรวจสอบข้อยกเว้นที่ตรวจสอบ (แม้ว่านี่อาจเป็นเหตุผลได้ก็ตาม)

เหตุผลที่จะไม่ใช้ข้อยกเว้น:

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

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

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

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


5

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

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


5

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

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


ฉันชอบความคิดเห็นของคุณเกี่ยวกับข้อยกเว้นภายในลูปและคิดว่าจะลองด้วยตัวเอง ฉันเขียนโปรแกรมตัวอย่างที่ใช้int.MaxValueเวลาวนรอบและสร้างข้อยกเว้น 'หารด้วยศูนย์' ในนั้น รุ่น IF / ELSE ที่ฉันตรวจสอบว่าเงินปันผลไม่เป็นศูนย์ก่อนการดำเนินการหารเสร็จใน 6082 ms และ 15407722 ติ๊กในขณะที่รุ่น TRY / CATCH ซึ่งฉันสร้างข้อยกเว้นและรับข้อยกเว้นเสร็จสมบูรณ์ใน 28174385 ms และ 71371326155 เห็บ: a whopping 4632 ครั้งมากกว่ารุ่น if / else
user1451111

3

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

ฉันต้องการเพิ่มโปรดส่งข้อยกเว้นมาตรฐาน ยกเว้นว่าคุณกำลังจะทำสิ่งที่ "แตกต่าง" (ไม่สนใจอีเมลบันทึกแสดงว่าภาพปลาวาฬทวิตเตอร์ thingy ฯลฯ ) จากนั้นอย่ารำคาญกับข้อยกเว้นที่กำหนดเอง


3

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

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


2

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

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

พวกมันคือ "ข้อยกเว้น" ถึงโฟลว์หลักของ UML ของคุณ แต่มี "สาขา" มากกว่าในการประมวลผล

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


" หากคุณพยายามเข้าถึงไฟล์หรือฐานข้อมูล passwd ของคุณและทำไม่ได้นั่นอาจเป็นกรณีพิเศษและรับประกันว่าจะมีข้อยกเว้น " กรอบภาษาส่วนใหญ่เช่น. NET Framework จะให้ API เพื่อตรวจสอบว่าไฟล์นั้นมีอยู่หรือไม่ ทำไมไม่ใช้พวกเขาก่อนที่จะเข้าถึงไฟล์โดยตรง!
user1451111

2

ประการแรกหากผู้ใช้ API ของคุณไม่สนใจความล้มเหลวที่เฉพาะเจาะจงและละเอียดแล้วมีข้อยกเว้นเฉพาะสำหรับพวกเขาจะไม่มีค่าใด ๆ

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


2

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


2

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


2

ฉันจะบอกว่าโดยทั่วไปทุกคนหวุดหวิดจะนำไปสู่นรก

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

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

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

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

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

ดังนั้นในตัวอย่างการลงชื่อเข้าใช้คุณควรสร้างบางสิ่งเช่น AuthenticationException และแยกแยะสถานการณ์ที่เป็นรูปธรรมด้วยค่า enum เช่นUsernameNotExisting , PasswordMismatchเป็นต้นจากนั้นคุณจะไม่ต้องมีลำดับชั้นของข้อยกเว้นจำนวนมากและสามารถเก็บ catch block ไว้ในระดับที่สามารถบำรุงรักษาได้ . นอกจากนี้คุณยังสามารถใช้กลไกการจัดการข้อยกเว้นทั่วไปบางอย่างได้ง่ายเนื่องจากคุณมีข้อยกเว้นที่จัดหมวดหมู่ไว้และรู้ว่าจะเผยแพร่สิ่งใดให้กับผู้ใช้ได้ดี

การใช้งานทั่วไปของเราคือการโยน LogicalException ระหว่างการโทรผ่าน Web Service เมื่อข้อมูลของผู้ใช้ไม่ถูกต้อง ข้อยกเว้นได้รับ marshalled ไปยังรายละเอียด SOAPFault แล้วได้รับ unmarshalled ไปยังข้อยกเว้นอีกครั้งบนไคลเอนต์ซึ่งมีผลในการแสดงข้อผิดพลาดในการตรวจสอบความถูกต้องในฟิลด์ป้อนข้อมูลหน้าเว็บหนึ่งเนื่องจากข้อยกเว้นมีการแมปที่เหมาะสมกับฟิลด์นั้น

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


2

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


1

เหตุผลหลักในการหลีกเลี่ยงการโยนข้อยกเว้นคือมีค่าใช้จ่ายจำนวนมากที่เกี่ยวข้องกับการโยนข้อยกเว้น

สิ่งหนึ่งที่บทความด้านล่างระบุว่ามีข้อยกเว้นสำหรับเงื่อนไขพิเศษและข้อผิดพลาด

ชื่อผู้ใช้ที่ไม่ถูกต้องไม่จำเป็นต้องเป็นข้อผิดพลาดของโปรแกรม แต่เป็นข้อผิดพลาดของผู้ใช้ ...

นี่คือจุดเริ่มต้นที่ดีสำหรับการยกเว้นภายใน. NET: http://msdn.microsoft.com/en-us/library/ms229030(VS.80).aspx


1

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

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


1

ฉันมีเงื่อนไขสามประเภทที่ฉันจับได้

  1. อินพุตที่ไม่ดีหรือหายไปไม่ควรเป็นข้อยกเว้น ใช้ js ฝั่งไคลเอ็นต์และ regex ฝั่งเซิร์ฟเวอร์เพื่อตรวจจับตั้งค่าแอ็ตทริบิวต์และส่งต่อกลับไปที่หน้าเดียวกันพร้อมข้อความ

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

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

หวังว่านี่จะช่วยได้


1

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


1

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

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

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

{ // class
    ...

    public LoginResult Login(string user, string password)
    {
        if (IsInvalidUser(user))
        {
            return new UserInvalidLoginResult(user);
        }
        else if (IsInvalidPassword(user, password))
        {
            return new PasswordInvalidLoginResult(user, password);
        }
        else
        {
            return new SuccessfulLoginResult();
        }
    }

    ...
}

public abstract class LoginResult
{
    public readonly string Message;

    protected LoginResult(string message)
    {
        this.Message = message;
    }
}

public class SuccessfulLoginResult : LoginResult
{
    public SucccessfulLogin(string user)
        : base(string.Format("Login for user '{0}' was successful.", user))
    { }
}

public class UserInvalidLoginResult : LoginResult
{
    public UserInvalidLoginResult(string user)
        : base(string.Format("The username '{0}' is invalid.", user))
    { }
}

public class PasswordInvalidLoginResult : LoginResult
{
    public PasswordInvalidLoginResult(string password, string user)
        : base(string.Format("The password '{0}' for username '{0}' is invalid.", password, user))
    { }
}

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

นี่คือตัวอย่างของการหลีกเลี่ยงการใช้ข้อยกเว้นในสถานการณ์เช่นเดียวกับที่อธิบายไว้โดยใช้รูปแบบลอง ():

public class ValidatedLogin
{
    public readonly string User;
    public readonly string Password;

    public ValidatedLogin(string user, string password)
    {
        if (IsInvalidUser(user))
        {
            throw new UserInvalidException(user);
        }
        else if (IsInvalidPassword(user, password))
        {
            throw new PasswordInvalidException(password);
        }

        this.User = user;
        this.Password = password;
    }

    public static bool TryCreate(string user, string password, out ValidatedLogin validatedLogin)
    {
        if (IsInvalidUser(user) || 
            IsInvalidPassword(user, password))
        {
            return false;
        }

        validatedLogin = new ValidatedLogin(user, password);

        return true;
    }
}

1

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

  exchange_command ("open tempfile");
  exchange_command ("เขียนข้อมูล tempfile {ก็ตาม}");
  exchange_command ("เขียนข้อมูล tempfile {ก็ตาม}");
  exchange_command ("เขียนข้อมูล tempfile {ก็ตาม}");
  exchange_command ("เขียนข้อมูล tempfile {ก็ตาม}");
  exchange_command ("close tempfile");
  exchange_command ("คัดลอก tempfile ไปยัง realfile");

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

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


1

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

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

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

ดังนั้นตามกฎของหัวแม่มือ:

ใช้พวกเขาทุกที่ที่คุณไม่ต้องการหรือไม่สามารถกู้คืนจากข้อผิดพลาด


0

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

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


0

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

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

0

มีข้อยกเว้นหลักสองประการ:

1) ข้อยกเว้นของระบบ (เช่นการเชื่อมต่อฐานข้อมูลสูญหาย) หรือ 2) ข้อยกเว้นของผู้ใช้ (เช่นการตรวจสอบการป้อนข้อมูลของผู้ใช้ 'รหัสผ่านไม่ถูกต้อง')

ฉันพบว่ามีประโยชน์ในการสร้าง User Exception Class ของตัวเองและเมื่อฉันต้องการโยนข้อผิดพลาดของผู้ใช้ฉันต้องการที่จะจัดการแตกต่างกัน (เช่นข้อผิดพลาด resourced แสดงให้ผู้ใช้) จากนั้นทั้งหมดที่ฉันต้องทำในตัวจัดการข้อผิดพลาดหลักคือ :

            If TypeName(ex) = "UserException" Then
               Display(ex.message)
            Else
               DisplayError("An unexpected error has occured, contact your help  desk")                   
               LogError(ex)
            End If

0

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

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

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

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