การจัดการข้อยกเว้น
| English | ไทย |
|---|---|
| exception/ekˈsepʃn/ | ข้อยกเว้น |
| exception handling/ekˈsepʃn ˈhændlɪŋ/ | การจัดการข้อยกเว้น |
| raise/reɪz/ | เพิ่ม |
การตรวจสอบที่ไม่สามารถเขียนโค้ดได้
- โปรแกรมเปิดไฟล์ ก่อนเปิดคุณอาจตรวจสอบได้ว่าไฟล์มีอยู่, อ่านได้, และไดรฟ์มีอยู่ สมมติว่าทุกการตรวจสอบผ่าน
- ระหว่างการตรวจสอบล่าสุดกับการเปิด ผู้ใช้ดึง USB Stick ออก ไฟล์มีอยู่เมื่อคุณถามและไม่อยู่เมื่อคุณเปิด และไม่มีวิธีการตรวจสอบล่วงหน้าใดจะปิดช่องว่างนี้ได้
- บางข้อผิดพลาดป้องกันไม่ได้ เพราะโลกเปลี่ยนแปลงระหว่างการทดสอบและการกระทำ สิ่งที่โปรแกรมทำได้คือ ตอบสนอง ต่อเมื่อมันเกิดขึ้น
- บทเรียนนี้คือ ข้อยกเว้น โครงสร้าง TRY ที่จัดการหนึ่งกรณี และตำแหน่งที่ควรจับข้อยกเว้นในโปรแกรม
ข้อยกเว้นคืออะไรและทำไมต้องจัดการ
- ข้อยกเว้น คือ ข้อผิดพลาดที่เกิดขึ้นระหว่างการทำงาน: การหารด้วยศูนย์, ไม่พบไฟล์, ข้อมูลไม่ถูกต้อง, เครือข่ายที่หายไป
- การจัดการข้อยกเว้น ช่วยให้โปรแกรม ตรวจจับ ข้อผิดพลาดและตอบสนอง以一种_seq的方式, แทนที่จะพังและเสียงานของผู้ใช้
- โปรแกรมจริงมักเจอข้อผิดพลาดที่ ไม่สามารถป้องกันล่วงหน้าได้ ตามที่ภาพแสดง และหากไม่มีระบบจัดการข้อยกเว้น การดำเนินการแต่ละขั้นตอนจะต้องมีการตรวจสอบ
IFแยกกันทั้งหมด ซึ่งจะทำให้อัลกอริทึมหลักถูกซ่อนอยู่ภายใต้การทดสอบความผิดพลาด - ประโยชน์ที่สามคือสิ่งที่ข้อสอบถามบ่อยที่สุด: มัน แยก กระบวนการปกติออกจากการจัดการข้อผิดพลาด ทำให้เส้นทางหลักอ่านง่าย
An exception is:
ข้อยกเว้นคือปัญหาที่ เกิดขึ้นขณะรันโปรแกรม (เช่นหารด้วยศูนย์, ไม่พบไฟล์) การจัดการกับข้อยกเว้นช่วยให้คุณสามารถตอบโต้ได้อย่างเหมาะสม
ทำไมต้องใช้การจัดการกับข้อยกเว้นแทนการตรวจสอบความผิดพลาดทั้งหมดล่วงหน้า? เลือก ทุก ข้อที่ถูกต้อง
ประโยชน์หลักคือความถูกต้องและความชัดเจน ความเร็วไม่ใช่其中之一; การจัดการกับข้อยกเว้นมีค่าใช้จ่ายทางประสิทธิภาพเล็กน้อยแต่คุ้มค่าที่จะจ่าย
โครงสร้าง TRY
TRY
OPENFILE "data.txt" FOR READ
READFILE "data.txt", line
CLOSEFILE "data.txt"
EXCEPT FileNotFound
OUTPUT "Sorry, the file does not exist."
EXCEPT ReadError
OUTPUT "Sorry, there was an error reading the file."
FINALLY
OUTPUT "Finished attempting to read."
ENDTRY
- บล็อก TRY เก็บโค้ดที่อาจล้มเหลว หากโค้ดนั้นทำงานโดยไม่เกิดข้อผิดพลาด บล็อก EXCEPT จะถูกข้ามไปทั้งหมด
- เมื่อเกิดข้อยกเว้น การทำงานจะกระโดดไปยัง บล็อก EXCEPT ที่ตรงกันเป็นอันดับแรก ทันที ส่วนที่เหลือของบล็อก TRY จะไม่ทำงาน
- บล็อก FINALLY จะทำงาน ไม่ว่าจะมีหรือไม่มี ข้อยกภัยเกิดขึ้น จึงเหมาะสำหรับการทำความสะอาด เช่น การปิดไฟล์

เส้นทางหนึ่งเมื่อทุกอย่างปกติ อีกเส้นทางหนึ่งเมื่อมีปัญหา และอีกเส้นทางหนึ่งที่ทำงานเสมอ
การทำงานของการจัดการข้อยกเว้นเป็นอย่างไร
ผ่านกระบวนการ发生的事情เมื่อโค้ดล้มเหลว ข้อยกเว้นจะกระโดดออกจากปกติ流向到一个 handler, FINALLY จะทำความสะอาดไม่ว่ากรณีใด และโปรแกรมจะดำเนินต่อไปแทนที่จะล่ม
จับคู่คำคีย์เวิร์ดสำหรับการจัดการกับข้อยกเว้นกับหน้าที่ของมัน
TRY ปกป้องโค้ดเสี่ยง, EXCEPT จับข้อยกเว้น, FINALLY เคลียร์งานไม่ว่าจะเกิดอะไรขึ้น, RAISE ทิ้งข้อผิดพลาดให้ถูกจับ
บล็อค FINALLY:
FINALLY ทำงานเสมอ ทำให้เหมาะสำหรับการเคลียร์งาน เช่น การปิดไฟล์
บล็อคที่ทำงานไม่ว่าจะมีข้อยกเว้นเกิดขึ้นหรือไม่ ทำให้เหมาะสำหรับการปิดไฟล์ คือ ____.
การเคลียร์งานต้องเกิดขึ้นในทั้งสองเส้นทาง การวาง CLOSEFILE ไว้ในบล็อค TRY เท่านั้น หมายความว่าจะถูกข้ามไปพอดีเมื่อมีข้อผิดพลาดทำให้ไฟล์เปิดค้างไว้
ตัวอย่างวิธีทำ: ติดตามลำดับการทำงาน
- ในโค้ดข้างต้น ไฟล์ไม่-existent ให้ระบุอย่างชัดเจนว่าอะไรจะถูกพิมพ์ออกมาและอะไรจะถูกข้ามไป
OPENFILEทำให้เกิด FileNotFound ดังนั้นการทำงานจะออกจากบล็อก TRY ทันที: บรรทัดREADFILEและCLOSEFILEจะไม่เคยถูกทำงาน- บล็อก
FileNotFoundEXCEPT จะทำงาน โดยพิมพ์ข้อความ "Sorry, the file does not exist." บล็อกReadErrorจะ ไม่ ทำงาน เพราะใช้ตัวจัดการที่ตรงกันเป็นอันดับแรกเท่านั้น - บล็อก FINALLY จะทำงาน โดยพิมพ์ข้อความ "Finished attempting to read."
- คะแนนที่มักหายมากที่สุดคือการไม่สังเกตว่าส่วนที่เหลือของบล็อก TRY ถูกทิ้งไว้
ไฟล์ในบล็อค TRY ไม่มีอยู่จริง เรียงลำดับสิ่งที่เกิดขึ้น
มีเพียงตัวจับข้อยกเว้นที่ตรงกันครั้งแรกเท่านั้นที่ทำงาน และ FINALLY จะทำงานไม่ว่าจะเกิดอะไรขึ้น ส่วนที่เหลือของบล็อค TRY ที่ถูกข้ามไปเป็นจุดที่คนมักพลาดมากที่สุด
การสร้างข้อยกภัย (Raising an exception)
- ฟังก์ชันย่อยที่ตรวจพบปัญหาที่มันแก้ไขไม่ได้อย่างสมเหตุสมผล สามารถ สร้าง (raise) ข้อยกภัยขึ้นเพื่อส่งความรับผิดชอบให้ผู้ที่เรียกใช้งาน:
IF b = 0 THEN RAISE DivideByZero
- นี่คือแบบแผนการออกแบบที่เหมาะสมเมื่อฟังก์ชันย่อยรู้ว่ามีอะไรผิดปกติแต่ไม่รู้ว่าจะทำอะไรดี กระบวนการหารรู้ว่าตัวหารเป็นศูนย์ แต่เพียงผู้เรียกใช้งานเท่านั้นที่รู้ว่าจะให้ผู้ใช้ลองใหม่ ใช้ค่าเริ่มต้น หรือเลิกการคำนวณ
subroutine ใช้ RAISE เพื่อ:
RAISE ทิ้งข้อยกเว้นกลับไปยังผู้เรียกใช้ ซึ่งสามารถจับได้ด้วย EXCEPT
ทำไม subroutine การหารถึงควร RAISE ข้อยกเว้นแทนที่จะจัดการกับตัวหารเป็นศูนย์เอง?
ให้ผู้ใช้ลองใหม่, ใช้ค่าเริ่มต้น, หรือยกเลิกการคำนวณ: มีเพียงโค้ดที่เรียกใช้เท่านั้นที่มีบริบทในการเลือก
ตำแหน่งในการจัดการ
- จัดการข้อยกภัย ใกล้กับจุดที่เกิด เมื่อการตอบสนองนั้นง่ายและเป็นภายในพื้นที่: พิมพ์ข้อความ, ใช้ค่าเริ่มต้น, หรือให้ผู้ใช้ลองอีกครั้ง
- จัดการ ในระดับที่สูงขึ้น เมื่อการตัดสินใจขึ้นอยู่กับส่วนที่ใหญ่กว่าของโปรแกรม: whether to abandon a whole transaction, rollback a change, or tell the user the operation failed.
- กฎทั่วไป: จับข้อยกภัยในระดับที่มีข้อมูลเพียงพอที่จะตัดสินใจว่าต้อง ทำอะไร ไม่ใช่ระดับที่ตรวจจับปัญหาเป็นครั้งแรก
ตัวอย่างวิธีทำ: สิ่งที่ไม่ควรทำ
- นักเขียนโปรแกรมใส่
EXCEPT: (do nothing)ล้อมรอบโปรแกรมนทั้งตัวเพื่อให้มันไม่พังเสมอไป อธิบายว่าทำไมสิ่งนี้จึงเป็นวิธีปฏิบัติที่ไม่ดี - การจัดการกับข้อยกเว้นถูก กลืนกิน: โปรแกรมจะทำงานต่อไปราวกับว่าไม่มีอะไรผิดพลาด occurrence จึงนำข้อมูลที่ยังไม่สมบูรณ์หรือข้อมูลที่ไม่ถูกต้องไปใช้ต่อและสร้างผลลัพธ์ที่ผิดแทนที่จะเกิดความล้มเหลวอย่างชัดเจน
- ความล้มเหลวแบบเงียบๆ ตรวจสอบได้ยากกว่า การพัง เพราะไม่มีข้อความแจ้งเตือนและไม่มีการบอกรูปแบบหรือตำแหน่งที่เกิดปัญหา
- การจับ ทุก ข้อยกเว้นไว้ในที่เดียวยังทำให้สูญเสียประเภทข้อผิดพลาดเฉพาะเจาะจงไว้ด้วย ทำให้ไม่สามารถเลือกการตอบสนองที่เหมาะสมได้ ตัวจัดการควรจับข้อยกเว้นที่มี ลักษณะเฉพาะ และตอบโต้กับมันจริง ๆ
การ "กลืน" ข้อยกเว้นอย่างเงียบๆ (จับแล้ว不做อะไร) ซ่อนข้อผิดพลาดจริงและทำให้การแก้ไขยาก — คุณควรจัดการกับมันหรืออย่างน้อยก็บันทึก日志
ตัวจับข้อยกเว้นที่ว่างเปล่าซ่อนปัญหาที่คุณจำเป็นต้องค้นหา; ต้องตอบสนองหรือบันทึกข้อผิดพลาดเสมอ
คะแนนที่หลุดหายไป
- เมื่อเกิดข้อยกเว้น ส่วนที่เหลือของบล็อก TRY จะถูกข้าม ให้ระบุจุดนี้เมื่อทำ Trace
- มีเพียง EXCEPT ที่ตรงกันตัวแรก เท่านั้นที่จะทำงาน ไม่ใช่ทั้งหมด
- FINALLY ทำงานเสมอ ไม่ว่าจะเป็นเมื่อมีข้อผิดพลาดหรือไม่ ซึ่งนี่คือเหตุผลที่ทำให้มันเหมาะสำหรับการปิดไฟล์
- อย่าจับข้อยกเว้นแล้ว不做อะไร (do nothing) ข้อผิดพลาดที่ถูกกลืนกินนั้นแย่กว่าการพัง เพราะโปรแกรมจะดำเนินต่อไปด้วยข้อมูลที่เสียหาย
คุณเข้าใจแล้ว
- ข้อยกเว้น (exception) คือข้อผิดพลาดระดับ运行时 (run-time); การจัดการกับมันช่วยให้โปรแกรมสามารถตอบสนองได้แทนที่จะพัง ครอบคลุมข้อผิดพลาดที่ ไม่สามารถป้องกันล่วงหน้าได้ และ แยก โค้ดปกติออกจากโค้ดจัดการข้อผิดพลาด
- TRY เก็บโค้ดที่มีความเสี่ยง; เมื่อเกิดข้อผิดพลาด ส่วนที่เหลือจะถูก ข้าม และ EXCEPT ที่ตรงกันตัวแรก จะทำงาน; FINALLY ทำงานไม่ว่ากรณีใด ดังนั้นการทำความสะอาด (cleanup) ควรอยู่ใน那里
- ฟังก์ชันย่อยที่ไม่สามารถตัดสินใจเลือกการตอบสนองได้ควร RAISE ข้อยกเว้นให้ caller ของมัน
- จัดการใกล้ๆ เพื่อการตอบสนองเฉพาะที่ง่าย ๆ หรือจัดHigher up เมื่อการตัดสินใจต้องการมุมมองที่กว้างขึ้น; ห้ามจับมันแล้ว不做อะไร (do nothing) ever