คำภาษาอังกฤษที่ผิดปกติเป็นข้อยกเว้นและการแปลตามตัวอักษรหมายถึง "อุบัติเหตุข้อยกเว้น" ซึ่งหมายถึงสถานการณ์ที่ผิดปกติ ในความเป็นจริงข้อยกเว้นเป็นข้อผิดพลาดของโปรแกรมเป็นหลักรวมถึงข้อผิดพลาดของลอจิกของโปรแกรมและข้อผิดพลาดของระบบ
คำนำ
ทุกคนคุ้นเคยกับการจัดการข้อยกเว้น Java โดยทั่วไปมีสองจุด:
1. โยนข้อยกเว้น: โยนข้อยกเว้น
คลาส SimpleException {โมฆะสาธารณะ A () โยนข้อยกเว้น {โยนข้อยกเว้นใหม่ (); -2. จับข้อยกเว้น:
คลาสสาธารณะ myexception {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {myexception e = new myexception (); SimpleException se = new SimpleException (); ลอง {se.a (); } catch (Exception e1) {e1.printstacktrace (); }}} คลาส SimpleException {โมฆะสาธารณะ A () โยนข้อยกเว้น {โยนข้อยกเว้นใหม่ (); -บทความนี้จะหารือเกี่ยวกับรายละเอียดบางอย่างเกี่ยวกับข้อมูลเชิงลึกเพิ่มเติมนี้
สองคลาสข้อยกเว้นแบบกำหนดเอง
ภาษา Java ให้เรามีชั้นเรียนยกเว้นมากมาย แต่บางครั้งเรายังต้องปรับแต่งคลาสข้อยกเว้นเพื่อความสะดวกในการเขียนโค้ด:
คลาส SimpleException ขยายข้อยกเว้น {};
หลังจากสร้างเราสามารถใช้ลองจับเพื่อจับภาพ:
คลาสสาธารณะ myexception {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {myexception e = new myexception (); ลอง {ea (); } catch (simpleException e1) {e1.printStackTrace (); }} โมฆะสาธารณะ A () พ่น SimpleException {โยน New SimpleException (); }} คลาส SimpleException ขยายข้อยกเว้น {};เรากำหนดวิธี A () ใน MyException ปล่อยให้มันโยนข้อยกเว้น SimpleEexception จากนั้นเราเรียกวิธีนี้ใน Main () และจับข้อยกเว้นนี้โดยใช้ Try Catch:
SimpleException ที่ myexception.a (myexception.java:15) ที่ myexception.main (myexception.java:8) ที่ sun.reflect.nativemethodaccessorimpl.invoke0 sun.reflect.delegatingMethodaccessorimpl.invoke (มอบหมาย Methodaccessorimpl.java:43) ที่ java.lang.reflect.method.invoke (method.java:606) ที่ com.intellij.rt.execution.application
ผลลัพธ์หลังจากการรวบรวมและการดำเนินการส่วนใหญ่ขึ้นอยู่กับสามบรรทัดแรก นี่คือบางประเด็นที่จะอธิบาย:
1. ระบุประเภทข้อยกเว้น: (ข้อกำหนดข้อยกเว้น)
เมื่อเราต้องการโยนข้อยกเว้นในวิธีการเราใช้การโยนและเพิ่มอินสแตนซ์ของคลาสข้อยกเว้น โปรแกรมจะโยนข้อยกเว้นที่สอดคล้องกันไปยังโปรแกรมไคลเอนต์ (โปรแกรมที่เรียกรหัสนี้) และออกที่นี่ (เทียบเท่ากับการส่งคืน) โปรดทราบว่าเราต้องระบุประเภทข้อยกเว้นเมื่อกำหนดวิธีนี้ ตัวอย่างเช่นรหัสต่อไปนี้จะส่งข้อยกเว้น SimpleException
โมฆะสาธารณะ a () พ่น simpleexception
2. โยนข้อยกเว้นหลายข้อ:
โมฆะสาธารณะ A () พ่น SimpleException, Aexception, Bexception {โยน New SimpleException (); -คลาสข้อยกเว้นที่แตกต่างกันสามารถคั่นด้วยเครื่องหมายจุลภาค ในกรณีนี้เราไม่จำเป็นต้องโยนแต่ละอินสแตนซ์ข้อยกเว้น () แต่รหัสไคลเอนต์จะต้องจับแต่ละคลาสข้อยกเว้น:
คลาสสาธารณะ myexception {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {myexception e = new myexception (); ลอง {ea (); } catch (simpleException e1) {e1.printStackTrace (); } catch (bexception e1) {e1.printstacktrace (); } catch (aexception e1) {e1.printstacktrace (); }} โมฆะสาธารณะ a () พ่น SimpleException, aException, bexception {โยน simpleException ใหม่ (); }} คลาส SimpleException ขยายข้อยกเว้น {}; คลาส aexception ขยายข้อยกเว้น {} คลาส bexception ขยายข้อยกเว้น {} ร่องรอยสามสแต็ก
ไม่ว่าจะเป็นการขว้างข้อยกเว้นหรือการจับและจัดการข้อยกเว้นวัตถุประสงค์ของเราคือการเขียนโปรแกรมที่มีประสิทธิภาพมากขึ้นซึ่งขึ้นอยู่กับข้อมูลข้อยกเว้นที่ได้รับจากกลไกการยกเว้น Java และผู้ให้บริการของมันคือการติดตามสแต็ก
ในรหัสก่อนหน้าเราใช้ PrintStackTrace () โดยตรงเพื่อพิมพ์ข้อมูลข้อยกเว้น ในความเป็นจริงเรายังสามารถใช้วิธี getStackTrace () เพื่อรับคอลเลกชันของ stacktraceelement หากคุณมีความคิดในมือคุณสามารถค้นหาคลาส stacktracelement ก่อนและคุณสามารถพบว่ามันใช้อินเทอร์เฟซ serializable แล้วดูคำอธิบายคลาส:
/** * องค์ประกอบในการติดตามสแต็กซึ่งส่งคืนโดย {@link * throwable#getStackTrace ()} แต่ละองค์ประกอบแสดงถึงเฟรมสแต็กเดียว * เฟรมสแต็กทั้งหมดยกเว้นอันที่ด้านบนของสแต็กแสดงถึงการเรียกใช้วิธีการ เฟรมที่ด้านบนของสแต็กแสดงถึงจุดดำเนินการ * ที่สร้างร่องรอยสแต็ก โดยทั่วไป * นี่คือจุดที่สร้างขึ้นซึ่งสอดคล้องกับสแต็กร่องรอย * ถูกสร้างขึ้น * * @Since 1.4 * @author Josh Bloch */เป็นที่ชัดเจนว่าแต่ละอินสแตนซ์ของคลาสนี้เป็นองค์ประกอบของการติดตามสแต็กซึ่งเป็นตัวแทนของเฟรมสแต็กและการติดตามสแต็กจะถูกส่งคืนโดยวิธี getStackTrace () ฉันพยายามแปลสิ่งต่อไปนี้หลายครั้ง แต่ฉันรู้สึกว่ามันไม่ดีดังนั้นฉันจึงสามารถเขียนรหัสโดยตรงเพื่ออธิบาย:
คลาสสาธารณะ myexception {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {myexception e = new myexception (); ea (); โมฆะสาธารณะ A () {ลอง {โยนข้อยกเว้นใหม่ (); } catch (exception e) {stacktracelement [] ste = e.getstacktrace (); System.out.println (Ste.Length); -เรากำหนดวิธี A ให้มันโยนข้อยกเว้นในขณะที่จับมันแล้วเราจะได้รับอาร์เรย์ stacktracelement ผ่านวิธี getStackTrace () และพิมพ์ความยาวของอาร์เรย์:
7
กระบวนการเสร็จสิ้นด้วยรหัสออก 0
เราเปลี่ยนรหัสเล็กน้อยและหยุดจับข้อยกเว้นใน เรากำหนดวิธี B ใหม่เพื่อให้ได้ข้อยกเว้นในขณะที่เรียก A:
คลาสสาธารณะ myexception {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {myexception e = new myexception (); eb (); } โมฆะสาธารณะ b () {ลอง {a (); } catch (exception e) {stacktracelement [] ste = e.getstacktrace (); System.out.println (Ste.Length); }} โมฆะสาธารณะ A () โยนข้อยกเว้น {โยนข้อยกเว้นใหม่ (); -ผลลัพธ์มีดังนี้:
8
กระบวนการเสร็จสิ้นด้วยรหัสออก 0
ไม่ต้องกังวลมาดูสิ่งที่น่าสนใจ:
คลาสสาธารณะ myexception {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {myexception exception = new myexception (); ลอง {exception.c (); } catch (exception e) {stacktracelement [] ste = e.getstacktrace (); System.out.println (Ste.Length); System.out.println ("-------------------------------------------------------"); สำหรับ (stackTraceElement S: e.getStackTrace ()) {system.out.println (s.getClassName ()+": method"+s.getMethodname ()+"ที่บรรทัด"+s.getLineNumber ()); } system.out.println ("-------------------------------------------------------"); }} โมฆะสาธารณะ c () พ่นข้อยกเว้น {ลอง {a (); } catch (exception e) {โยน e; }} โมฆะสาธารณะ A () โยนข้อยกเว้น {โยนข้อยกเว้นใหม่ (); -นี่คือผลลัพธ์:
8 ----------------------------------------------------------- MyException: วิธี A ที่ line43MyException: วิธี C ที่ line39MyException: วิธีการหลักที่ line9Sun.reflect.nativeMethodaccessorimpl: วิธีการเรียกใช้ที่ line-2sun.reflect.nativemethodaccessorimpl line57sun.reflect.delegatingmethodaccessorimpl: วิธีการเรียกใช้ที่ line43java.lang.reflect.method: วิธีการเรียกใช้ที่ line606com.intellij.rt.execution.application.appmain: วิธีการหลักที่ line144 ----------------------------------------------------------
กล่าวคือ getStackTrace () ส่งคืนสแต็กซึ่งมีข้อมูลพื้นฐานบางอย่างจากผู้โทร (หลัก ()) ไปยังข้อยกเว้นการขว้างปาเริ่มต้น (a ()) ในรหัสข้างต้นเราจับข้อยกเว้นเมื่อเรียกวิธี A ในวิธี C และโยนมันอีกครั้งผ่านการโยน วิธีการเรียกวิธี C สามารถจับและจัดการกับข้อยกเว้นหรือคุณสามารถเลือกที่จะขว้างปาเพื่อให้ผู้โทรระดับสูงกว่า (ใกล้ด้านล่างของสแต็ก) จัดการกับมัน แม้ว่า Rethrow จะสะดวกมาก แต่ก็มีปัญหาบางอย่าง มาดูรหัสต่อไปนี้:
คลาสสาธารณะ myexception {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {myexception exception = new myexception (); ลอง {exception.c (); } catch (exception e) {e.printstacktrace (system.out); }} โมฆะสาธารณะ c () พ่นข้อยกเว้น {ลอง {a (); } catch (exception e) {โยน e; }} โมฆะสาธารณะ A () โยนข้อยกเว้น {โยนข้อยกเว้นใหม่ ("ข้อยกเว้นจาก ()"); }} java.lang.exception: ข้อยกเว้นจาก a () ที่ myexception.a (myexception.java:40) ที่ myexception.c (myexception.java:30) ที่ myexception.main (myexception.java:21)เราโยน E อีกครั้งใน C และพิมพ์ออกมาโดยใช้ E.PrintStackTrace () ในหลัก คุณจะเห็นว่าการติดตามสแต็กที่พิมพ์ยังคงเป็นของ หากเราต้องการเปลี่ยนการติดตามสแต็กเป็น C เราสามารถเขียนได้เช่นนี้:
คลาสสาธารณะ myexception {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {myexception exception = new myexception (); ลอง {exception.c (); } catch (exception e) {e.printstacktrace (system.out); }} โมฆะสาธารณะ c () พ่นข้อยกเว้น {ลอง {a (); } catch (exception e) {// throw e; โยน (ข้อยกเว้น) e.fillinstacktrace (); }} โมฆะสาธารณะ A () โยนข้อยกเว้น {โยนข้อยกเว้นใหม่ ("ข้อยกเว้นจาก ()"); }} java.lang.exception: ข้อยกเว้นจาก a () ที่ myexception.c (myexception.java:22) ที่ myexception.main (myexception.java:10) สี่ข้อยกเว้นการผูกมัด
มาดูสถานการณ์:
Public Class Testexception {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {testexception testexception = testException ใหม่ (); ลอง {testexception.c (); } catch (cexception e) {e.printstacktrace (); }} โมฆะสาธารณะ A () พ่น AException {aException aException = ใหม่ aException ("นี่คือข้อยกเว้น"); โยน aexception; } โมฆะสาธารณะ b () พ่น bexception {ลอง {a (); } catch (aexception e) {โยน bexception ใหม่ ("นี่คือข้อยกเว้น b"); }} โมฆะสาธารณะ c () พ่น cexception {ลอง {b (); } catch (bexception e) {โยน cexception ใหม่ ("นี่คือข้อยกเว้น c"); }}} คลาส aexception ขยายข้อยกเว้น {aException สาธารณะ (String msg) {super (msg); }} คลาส bexception ขยายข้อยกเว้น {public bexception (string msg) {super (msg); }} คลาส cexception ขยายข้อยกเว้น {public cexception (String msg) {super (msg); -สามคลาสข้อยกเว้น aexception, bexception และ cexception ถูกสร้างขึ้นจากนั้น aexception จะถูกโยนลงใน (), aexception ถูกจับใน b () และ bexception ถูกโยนลงและในที่สุด bexception ถูกจับใน c () และ cexception ถูกโยนลงไป
Cexception: นี่คือข้อยกเว้น C ที่ testexception.c (testexception.java:31) ที่ testexception.main (testexception.java:8)
ตกลงเราเห็นเฉพาะข้อมูลของ cexception, aexception และ bexception หายไปและฟังก์ชั่นของห่วงโซ่ยกเว้นจะออกมาดูรหัส:
Public Class Testexception {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {testexception testexception = testException ใหม่ (); ลอง {testexception.c (); } catch (cexception e) {e.printstacktrace (); }} โมฆะสาธารณะ A () พ่น AException {aException aException = ใหม่ aException ("นี่คือข้อยกเว้น"); โยน aexception; } โมฆะสาธารณะ b () พ่น bexception {ลอง {a (); } catch (aexception e) {// โยน bexception ใหม่ ("นี่คือข้อยกเว้น b"); bexception bexception = new bexception ("นี่คือข้อยกเว้น b"); bexception.initcause (e); โยน bexception; }} โมฆะสาธารณะ c () พ่น cexception {ลอง {b (); } catch (bexception e) {// โยน cexception ใหม่ ("นี่คือข้อยกเว้น c"); cexception cexception = new cexception ("นี่คือข้อยกเว้น c"); cexception.initcause (e); โยน cexception; }}} คลาส aexception ขยายข้อยกเว้น {aException สาธารณะ (String msg) {super (msg); }} คลาส bexception ขยายข้อยกเว้น {public bexception (string msg) {super (msg); }} คลาส cexception ขยายข้อยกเว้น {public cexception (String msg) {super (msg); -เราใช้วิธีการเริ่มต้น () เพื่อเชื่อมต่อข้อมูลข้อยกเว้นและผลลัพธ์มีดังนี้:
Cexception: นี่คือข้อยกเว้น C ที่ testexception.c (testexception.java:35) ที่ testexception.main (testexception.java:8) ที่ sun.reflect.nativemethodaccessorimpl.invoke0 sun.reflect.delegatingMethodaccessorimpl.invoke (มอบหมาย Methodaccessorimpl.java:43) ที่ java.lang.reflect.method.invoke (method.java:606) ที่ com.intellij.rt.execution.application B ข้อยกเว้นที่ testexception.b (testexception.java:24) ที่ testexception.c (testexception.java:32) ... 6 morecaused โดย: aexception: นี่คือข้อยกเว้นที่ testexception.a (testexception.java:15) ที่ testexception.b
ห้า postscript
ในความเป็นจริงยังมีอีกหลายสิ่งที่จะพูดคุยเกี่ยวกับการจัดการข้อยกเว้น Java แต่เนื่องจากฉันมีประสบการณ์ที่ จำกัด ฉันจึงไม่เข้าใจลึกเกินไปและสิ่งที่ใช้กันมากที่สุดคือ
ลอง {... } catch (Exception e) {... } ในที่สุด {// รหัสที่จะดำเนินการโดยไม่คำนึงว่าข้อยกเว้นจะถูกจับหรือประมวลผลเช่นการปิดการดำเนินงาน IO}แต่ไม่ว่าจะเกิดอะไรขึ้นเราก็ยังต้องขอบคุณ Java ที่ให้กลไกข้อยกเว้นแก่เรา มันเป็นเหมือนผู้อาวุโสชี้นำเราเป็นครั้งคราวและทำให้เราเบื่อน้อยลงเมื่อเข้ารหัส :)