การทำให้โปรแกรมสมบูรณ์แบบเป็นเรื่องยาก และย่อมมีความผิดปกติต่างๆ ตามมาอย่างหลีกเลี่ยงไม่ได้ เช่น มีจุดบกพร่องในตัวโปรแกรมเอง เช่น เครื่องพิมพ์กระดาษหมดเมื่อโปรแกรมพิมพ์ หรือมีหน่วยความจำไม่เพียงพอ เพื่อแก้ไขข้อยกเว้นเหล่านี้ เราจำเป็นต้องรู้ว่าเหตุใดจึงมีข้อยกเว้นเกิดขึ้น สำหรับข้อยกเว้นทั่วไปบางประการ เรายังสามารถจัดเตรียมแผนการรับมือบางอย่างได้ด้วย การจัดการข้อยกเว้นในภาษา C ดำเนินการอย่างง่ายดายผ่านค่าส่งคืนของฟังก์ชัน แต่ความหมายของค่าส่งคืนมักถูกกำหนดโดยแบบแผน โปรแกรมเมอร์จำเป็นต้องสืบค้นข้อมูลจำนวนมากก่อนจึงจะสามารถหาเหตุผลที่คลุมเครือได้ ภาษาเชิงวัตถุ เช่น C++, Java และ Python มักจะมีกลไกการจัดการข้อยกเว้นที่ซับซ้อนกว่า กลไกการจัดการข้อยกเว้นใน Java มีการกล่าวถึงที่นี่
การจัดการข้อยกเว้น Java
การจัดการข้อยกเว้น
กลไกการจัดการข้อยกเว้นของ Java ส่วนใหญ่มาจาก C++ ช่วยให้โปรแกรมเมอร์ข้ามปัญหาที่ไม่สามารถจัดการได้ชั่วคราวเพื่อดำเนินการพัฒนาต่อไป หรือเพื่อให้โปรแกรมจัดการข้อยกเว้นได้อย่างชาญฉลาดยิ่งขึ้น
Java ใช้วัตถุพิเศษบางอย่างเพื่อแสดงสภาวะที่ผิดปกติ วัตถุดังกล่าวเรียกว่าวัตถุข้อยกเว้น เมื่อมีข้อยกเว้นเกิดขึ้น Java จะส่งอ็อบเจ็กต์ที่แสดงถึงสถานการณ์ปัจจุบันตามการตั้งค่าที่ตั้งไว้ล่วงหน้า การขว้างที่เรียกว่าเป็นวิธีการตอบแทนแบบพิเศษ เธรดจะหยุดชั่วคราวและออกจากการเรียกเมธอดทีละชั้นจนกว่าจะพบตัวจัดการข้อยกเว้น ตัวจัดการข้อยกเว้นสามารถจับวัตถุข้อยกเว้นและตัดสินใจดำเนินการต่อไปตามวัตถุ เช่น:
เตือนผู้ใช้ให้จัดการกับข้อยกเว้นและดำเนินโปรแกรมต่อเพื่อออกจากโปรแกรม
-
ตัวจัดการข้อยกเว้นมีลักษณะดังนี้ ประกอบด้วย try, catch และบล็อกต่อไปนี้ ในที่สุดก็ไม่จำเป็น
ลอง { ...;}catch() { ...;}catch() { ...;}ในที่สุด { ...;}
ตัวจัดการข้อยกเว้นนี้จะตรวจสอบบล็อกโปรแกรมหลังจากลอง วงเล็บจับมีพารามิเตอร์ที่แสดงถึงประเภทของข้อยกเว้นที่จะจับ catch จะจับประเภทที่เกี่ยวข้องและคลาสที่ได้รับมา บล็อกโปรแกรมหลังจากการลองประกอบด้วยการดำเนินการที่จะดำเนินการสำหรับประเภทข้อยกเว้น บล็อกโปรแกรมที่ถูกตรวจสอบโดยการลองอาจมีข้อยกเว้นมากกว่าหนึ่งประเภท ดังนั้นตัวจัดการข้อยกเว้นสามารถมีโมดูล catch ได้หลายโมดูล โปรแกรมบล็อกหลังจากนั้นคือโปรแกรมที่ต้องดำเนินการโดยไม่คำนึงว่าจะมีข้อยกเว้นเกิดขึ้นหรือไม่
เราลองใช้โปรแกรมที่อาจผิดพลาดและจำเป็นต้องได้รับการตรวจสอบ และออกแบบโซลูชันเพื่อจัดการกับข้อยกเว้นที่ตามมา
ต่อไปนี้เป็นโปรแกรม Java บางส่วนที่ใช้การจัดการข้อยกเว้น ส่วนลองของโปรแกรมจะอ่านบรรทัดข้อความจากไฟล์ ในระหว่างกระบวนการอ่านไฟล์ IOException อาจเกิดขึ้น:
BufferedReader br = new BufferedReader(new FileReader("file.txt"));ลอง { StringBuilder sb = new StringBuilder(); String line = br.readLine(); while (line != null) { sb.append(line) ; sb.append("/n"); line = br.readLine(); } สตริงทุกอย่าง = sb.toString();} catch(IOException e) { e.printStackTrace(); System.out.println("ปัญหา IO");} ในที่สุด { br.close();}
หากเราจับวัตถุคลาส IOException e เราก็สามารถดำเนินการกับวัตถุได้ ตัวอย่างเช่น เรียก printStackTrace() ของอ็อบเจ็กต์เพื่อพิมพ์สถานะสแต็กปัจจุบัน นอกจากนี้เรายังพิมพ์ข้อความ "ปัญหา IO" ไว้ที่เสียงกลางด้วย
ไม่ว่าจะมีข้อยกเว้นหรือไม่ก็ตาม ในที่สุดโปรแกรมก็จะเข้าสู่บล็อกสุดท้าย เราปิดไฟล์ในบล็อกสุดท้ายและล้างทรัพยากรที่ตัวอธิบายไฟล์ครอบครอง
ประเภทข้อยกเว้น
คลาสข้อยกเว้นใน Java ทั้งหมดสืบทอดมาจากคลาส Trowable วัตถุในคลาส Throwable สามารถโยนได้ (โยน)
สีส้ม: ไม่เลือก สีฟ้า: เลือกแล้ว
วัตถุที่ขว้างได้สามารถแบ่งออกเป็นสองกลุ่ม กลุ่มหนึ่งเป็นข้อยกเว้นที่ไม่ได้ตรวจสอบ กลไกการจัดการข้อยกเว้นมักไม่ได้ใช้สำหรับข้อยกเว้นกลุ่มนี้ ได้แก่:
1. คลาส Error มักจะอ้างถึงข้อผิดพลาดภายในและข้อผิดพลาดของ Java เช่น การใช้ทรัพยากรจนหมด เมื่อเกิดข้อผิดพลาด (และอนุพันธ์ของมัน) เราไม่สามารถแก้ไขข้อผิดพลาดในระดับการเขียนโปรแกรมได้ ดังนั้นเราควรออกจากโปรแกรมโดยตรง
2. คลาส Exception มีคลาส RuntimeException ที่ได้รับมาเป็นพิเศษ RuntimeException (และอนุพันธ์ของมัน) เกิดจากโปรแกรม Java เองนั่นคือเนื่องจากโปรแกรมเมอร์ทำผิดพลาดขณะเขียนโปรแกรม RuntimeException สามารถหลีกเลี่ยงได้อย่างสมบูรณ์โดยการแก้ไขโปรแกรม Java ตัวอย่างเช่น การแปลงออบเจ็กต์ประเภทหนึ่งไปเป็นอีกประเภทหนึ่งโดยไม่มีความสัมพันธ์แบบสืบทอดคือ ClassCastException ความผิดปกติดังกล่าวควรและสามารถหลีกเลี่ยงได้
ส่วนที่เหลือจะถูกตรวจสอบข้อยกเว้น คลาสเหล่านี้เกิดจากการโต้ตอบการเขียนโปรแกรมกับสภาพแวดล้อมที่ทำให้เกิดข้อผิดพลาดในโปรแกรมขณะรันไทม์ ตัวอย่างเช่น เมื่ออ่านไฟล์ IOException จะเกิดขึ้นเนื่องจากข้อผิดพลาดในตัวไฟล์เอง อีกตัวอย่างหนึ่งคือเซิร์ฟเวอร์เครือข่ายเปลี่ยนการชี้ URL ชั่วคราว ทำให้เกิด MalformedURLException ระบบไฟล์และเซิร์ฟเวอร์เครือข่ายอยู่นอกสภาพแวดล้อม Java และไม่อยู่ในการควบคุมของโปรแกรมเมอร์ หากโปรแกรมเมอร์สามารถคาดการณ์ข้อยกเว้นได้ พวกเขาสามารถใช้กลไกการจัดการข้อยกเว้นเพื่อพัฒนาแผนการตอบสนองได้ เช่น เมื่อเกิดปัญหากับไฟล์ ผู้ดูแลระบบจะได้รับการแจ้งเตือน อีกตัวอย่างหนึ่งคือ เมื่อมีปัญหากับเซิร์ฟเวอร์เครือข่าย ผู้ใช้จะได้รับการเตือนและรอให้เซิร์ฟเวอร์เครือข่ายทำการกู้คืน กลไกการจัดการข้อยกเว้นส่วนใหญ่จะใช้เพื่อจัดการกับข้อยกเว้นดังกล่าว
โยนข้อยกเว้น
ในโปรแกรมข้างต้น ข้อยกเว้นมาจากการเรียก Java IO API ของเรา นอกจากนี้เรายังสามารถส่งข้อยกเว้นในโปรแกรมของเราเองได้ เช่น คลาสแบตเตอรี่ต่อไปนี้ ซึ่งมีวิธีการชาร์จและการใช้งาน:
การทดสอบคลาสสาธารณะ { public static void main (String [] args) { แบตเตอรี่ aBattery = แบตเตอรี่ใหม่ (); aBattery.chargeBattery (0.5); aBattery.useBattery (-0.5); / โมฆะสาธารณะ chargeBattery (p สองเท่า) { // power <= 1 ถ้า (this.power + p < 1.) { this.power = this.power + p; } else { this.power = 1.; } } /** * ใช้แบตเตอรี่ */ public boolean useBattery(double p) { try { test(p } catch(Exception e) { System. out.println("catch Exception"); System.out.println(e.getMessage()); p = 0.0; } ถ้า (this.power >= p) { this.power = this.power - p; return true; } else { this.power = 0.0; } } /** * test การใช้งาน */ private void test(double p) ส่งข้อยกเว้น // ฉันเพิ่งโยน, อย่าจัดการ { if ( p < 0) { ข้อยกเว้น e = ข้อยกเว้นใหม่ ("p ต้องเป็นบวก"); โยน e; } } กำลังสองเท่าส่วนตัว = 0.0;
useBattery() บ่งชี้ถึงการใช้งานแบตเตอรี่ มีพารามิเตอร์ในเมธอด useBattery() ซึ่งระบุปริมาณไฟฟ้าที่ใช้ เราใช้เมธอด test() เพื่อทดสอบพารามิเตอร์นี้ หากพารามิเตอร์นี้เป็นค่าลบ แสดงว่ามีข้อยกเว้นและโยนทิ้งไป
ในการทดสอบ เมื่อมีข้อยกเว้นเกิดขึ้น (p < 0) เราจะสร้างวัตถุข้อยกเว้น e และใช้สตริงเป็นพารามิเตอร์ สตริงประกอบด้วยข้อมูลที่เกี่ยวข้องกับข้อยกเว้น และพารามิเตอร์นี้ไม่จำเป็น ใช้โยนเพื่อโยนวัตถุข้อยกเว้น
เรามีตัวจัดการข้อยกเว้นใน useBattery() เนื่องจากเมธอด test() ไม่ได้จัดการข้อยกเว้นที่สร้างขึ้นโดยตรง แต่ส่งข้อยกเว้นไปที่ useBattery() ระดับบน เราจึงต้องอธิบายการ Throws Exception ในคำจำกัดความของ test()
(สมมติว่าตัวจัดการข้อยกเว้นไม่ได้อยู่ใน useBattery() แต่ในเมธอด main() ระดับที่สูงกว่า เรายังจำเป็นต้องเพิ่ม Throws Exception ให้กับคำจำกัดความของ useBattery())
เราใช้เมธอด getMessage() เพื่อดึงข้อมูลที่อยู่ในข้อยกเว้น ผลลัพธ์ของการรันโปรแกรมข้างต้นมีดังนี้:
catch Exceptionp ต้องเป็นค่าบวก
ในตัวจัดการข้อยกเว้น เราจะจับข้อยกเว้นของคลาส Exception หรืออนุพันธ์ของมัน ซึ่งมักจะไม่ช่วยให้เราระบุปัญหา โดยเฉพาะอย่างยิ่งเมื่อโปรแกรมอาจมีข้อยกเว้นหลายรายการ เราสามารถจัดเตรียมคลาสที่เฉพาะเจาะจงมากขึ้นในการจับภาพได้
ข้อยกเว้นที่กำหนดเอง
เราสามารถสร้างคลาสข้อยกเว้นใหม่ผ่านการสืบทอด เมื่อสืบทอด เรามักจะต้องแทนที่ตัวสร้าง ข้อยกเว้นมีตัวสร้างสองตัว ตัวหนึ่งไม่มีพารามิเตอร์ และอีกตัวหนึ่งมีพารามิเตอร์ String ตัวอย่างเช่น:
คลาส BatteryUsageException ขยายข้อยกเว้น { BatteryUsageException สาธารณะ () {} BatteryUsageException สาธารณะ (ข้อความข้อความ) { super (msg }}
เราสามารถจัดเตรียมวิธีการและข้อมูลที่เกี่ยวข้องกับข้อยกเว้นเพิ่มเติมในคลาสที่ได้รับ
เมื่อปรับแต่งข้อยกเว้น โปรดใช้ความระมัดระวังว่าคลาสพื้นฐานใดที่คุณสืบทอดมา คลาสที่เฉพาะเจาะจงมากขึ้นควรมีข้อมูลข้อยกเว้นมากขึ้น เช่น IOException กับ Exception
สรุป
การจัดการข้อยกเว้นคือการแก้ปัญหา แต่ก็ยังสร้างปัญหาด้วย ในโครงการขนาดใหญ่ การจัดการข้อยกเว้นอย่างละเอียดและมากเกินไปมักทำให้โปรแกรมเกิดความยุ่งเหยิง การออกแบบการจัดการข้อยกเว้นไม่ใช่เรื่องง่าย และจำเป็นต้องใช้ด้วยความระมัดระวัง