1. ประเภทของข้อยกเว้น

ข้อยกเว้นทั้งหมดแบ่งออกเป็น 4 ประเภทซึ่งเป็นคลาสที่สืบทอดซึ่งกันและกัน
Throwable
ระดับ
คลาสพื้นฐานสำหรับข้อยกเว้นทั้งหมดคือThrowable
คลาส คลาสThrowable
ประกอบด้วยโค้ดที่เขียน call stack ปัจจุบัน (stack trace ของเมธอดปัจจุบัน) ไปยังอาร์เรย์ เราจะเรียนรู้ว่าการติดตามสแต็กคืออะไรในภายหลัง
ตัว ดำเนิน การโยนสามารถยอมรับวัตถุที่มาจากThrowable
ชั้นเรียน เท่านั้น และแม้ว่าในทางทฤษฎีแล้วคุณสามารถเขียนโค้ดได้ แต่throw new Throwable();
มักจะไม่มีใครทำสิ่งนี้ จุดประสงค์หลักของThrowable
คลาสคือการมีคลาสพาเรนต์เดียวสำหรับข้อยกเว้นทั้งหมด
Error
ระดับ
คลาสยกเว้นถัดไปคือError
คลาสซึ่งสืบทอดThrowable
คลาส โดยตรง เครื่อง Java สร้างอ็อบเจกต์ของคลาสError
(และคลาสรอง) เมื่อเกิดปัญหาร้ายแรง ตัวอย่างเช่น ฮาร์ดแวร์ทำงานผิดปกติ หน่วยความจำไม่เพียงพอ เป็นต้น
โดยปกติแล้ว ในฐานะโปรแกรมเมอร์คุณไม่สามารถทำอะไรได้ในสถานการณ์ที่เกิดข้อผิดพลาด (ซึ่งError
ควรจะเกิดขึ้น) ในโปรแกรม ข้อผิดพลาดเหล่านี้ร้ายแรงเกินไป สิ่งที่คุณทำได้คือแจ้งให้ผู้ใช้ทราบว่าโปรแกรมขัดข้อง และ/หรือเขียนข้อมูลที่ทราบทั้งหมดเกี่ยวกับข้อผิดพลาดลงในบันทึกของโปรแกรม
Exception
ระดับ
และ คลาสสำหรับข้อผิดพลาดทั่วไปที่เกิด Exception
ขึ้นRuntimeException
ในการทำงานของเมธอดต่างๆ เป้าหมายของการโยนข้อยกเว้นแต่ละครั้งคือการถูกcatch
บล็อกที่รู้วิธีจัดการอย่างถูกต้อง
เมื่อเมธอดไม่สามารถทำงานให้เสร็จได้ด้วยเหตุผลบางประการ เมธอดควรแจ้งเมธอดการโทรทันทีโดยส่งข้อยกเว้นประเภทที่เหมาะสม
กล่าวอีกนัยหนึ่ง ถ้าตัวแปรเท่ากับnull
เมธอดจะโยนNullPointerException
a หากมีการส่งผ่านอาร์กิวเมนต์ที่ไม่ถูกต้องไปยังเมธอด มันจะโยนไฟล์InvalidArgumentException
. หากเมธอดนั้นหารด้วยศูนย์โดยไม่ตั้งใจ มันจะโยนไฟล์ArithmeticException
.
RuntimeException
ระดับ
RuntimeExceptions
เป็นส่วนย่อยExceptions
ของ เราอาจพูดได้ด้วยซ้ำว่าRuntimeException
เป็นข้อยกเว้นธรรมดารุ่นเล็ก ( Exception
) — มีการกำหนดข้อกำหนดและข้อจำกัดน้อยลงสำหรับข้อยกเว้นดังกล่าว
คุณจะได้เรียนรู้ความแตกต่างระหว่างException
และRuntimeException
ในภายหลัง
2. Throws
: ตรวจสอบข้อยกเว้น
ข้อยกเว้น Java ทั้งหมดแบ่งออกเป็น 2 ประเภท: ทำเครื่องหมายและไม่ได้ทำเครื่องหมาย
ข้อยกเว้นทั้งหมดที่สืบทอดRuntimeException
หรือError
ถือเป็นข้อยกเว้นที่ไม่ได้ตรวจสอบ ข้อยกเว้นอื่นๆ ทั้งหมดได้ รับการตรวจสอบ แล้ว
20 ปีหลังจากเปิดตัวข้อยกเว้นที่ตรวจสอบแล้ว โปรแกรมเมอร์ Java เกือบทุกคนคิดว่าสิ่งนี้เป็นข้อผิดพลาด ในเฟรมเวิร์กสมัยใหม่ยอดนิยม 95% ของข้อยกเว้นทั้งหมดไม่ถูกเลือก ภาษา C# ซึ่งเกือบจะคัดลอก Java ทุกประการ ไม่ได้เพิ่มข้อยกเว้นที่ตรวจสอบแล้ว
อะไรคือข้อแตกต่างที่สำคัญระหว่างข้อยกเว้นที่ตรวจสอบและไม่ได้ตรวจสอบ
มีข้อกำหนดเพิ่มเติมสำหรับข้อยกเว้นที่ตรวจสอบ พูดโดยคร่าว ๆ คือ:
ข้อกำหนด 1
หากเมธอดแสดงข้อยกเว้นที่ตรวจสอบจะ ต้อง ระบุประเภทของข้อยกเว้นในลายเซ็น ด้วยวิธีนี้ ทุกเมธอดที่เรียกใช้จะทราบว่า "ข้อยกเว้นที่มีความหมาย" นี้อาจเกิดขึ้นในนั้น
ระบุ ข้อยกเว้น ที่ตรวจสอบหลังพารามิเตอร์เมธอดหลังthrows
คีย์เวิร์ด (อย่าใช้throw
คีย์เวิร์ดโดยไม่ได้ตั้งใจ) ดูเหมือนว่า:
type method (parameters) throws exception
ตัวอย่าง:
ตรวจสอบข้อยกเว้น | ข้อยกเว้นที่ไม่ได้ตรวจสอบ |
---|---|
|
|
ในตัวอย่างด้านขวา โค้ดของเราแสดง ข้อยกเว้น ที่ไม่ได้ตรวจสอบ — ไม่จำเป็นต้องดำเนินการใดๆ เพิ่มเติม ในตัวอย่างทางด้านซ้าย เมธอดจะส่ง ข้อยกเว้น ที่ตรวจสอบดังนั้นthrows
คีย์เวิร์ดจึงถูกเพิ่มลงในลายเซ็นเมธอดพร้อมกับประเภทของข้อยกเว้น
หากเมธอดคาดว่าจะส่ง ข้อยกเว้น ที่ตรวจสอบ หลายรายการ จะต้องระบุทั้งหมดหลังthrows
คำสำคัญ โดยคั่นด้วยเครื่องหมายจุลภาค ลำดับไม่สำคัญ ตัวอย่าง:
public void calculate(int n) throws Exception, IOException
{
if (n == 0)
throw new Exception("n is null!");
if (n == 1)
throw new IOException("n is 1");
}
ข้อกำหนด 2
หากคุณเรียกใช้เมธอดที่มีการตรวจสอบข้อยกเว้นในลายเซ็นคุณจะไม่สามารถเพิกเฉยต่อข้อเท็จจริงที่ว่าเมธอดนั้นโยนทิ้งได้
คุณต้องจับข้อยกเว้นดังกล่าวทั้งหมดโดยเพิ่มcatch
บล็อกสำหรับแต่ละรายการ หรือโดยการเพิ่มในthrows
ส่วนคำสั่งสำหรับวิธีการของคุณ
เหมือนกับว่าเรากำลังพูดว่า " ข้อยกเว้นเหล่านี้สำคัญมากที่เราจะต้องจับมันให้ได้ และถ้าเราไม่รู้ว่าจะจัดการกับมันอย่างไร ใครก็ตามที่อาจเรียกใช้วิธีการของเรา จะต้องได้รับแจ้งว่าข้อยกเว้นดังกล่าวสามารถเกิดขึ้นได้ในนั้น
ตัวอย่าง:
ลองนึกภาพว่าเรากำลังเขียนวิธีการสร้างโลกที่มีมนุษย์อาศัยอยู่ จำนวนคนเริ่มต้นจะถูกส่งผ่านเป็นอาร์กิวเมนต์ เราจึงต้องเพิ่มข้อยกเว้นหากมีคนน้อยเกินไป
สร้างโลก | บันทึก |
---|---|
|
เมธอดนี้อาจมี ข้อยกเว้น ที่ตรวจสอบแล้ว สอง รายการ:
|
การเรียกใช้เมธอดนี้สามารถจัดการได้ 3 วิธี:
1. อย่าจับข้อยกเว้นใด ๆ
สิ่งนี้มักทำเมื่อวิธีการนี้ไม่ทราบวิธีจัดการกับสถานการณ์อย่างเหมาะสม
รหัส | บันทึก |
---|---|
|
เมธอดการโทรไม่จับข้อยกเว้นและต้องแจ้งให้ผู้อื่นทราบ: มันเพิ่มเข้าไปในthrows อนุประโยค ของมันเอง |
2. จับข้อยกเว้นบางประการ
เราจัดการกับข้อผิดพลาดที่เราจัดการได้ แต่อันที่เราไม่เข้าใจก็โยนไปตามวิธีการเรียก ในการทำเช่นนี้ เราจำเป็นต้องเพิ่มชื่อของพวกเขาในส่วนคำสั่งโยน:
รหัส | บันทึก |
---|---|
|
ผู้โทรจับข้อยกเว้นที่เลือกไว้เพียงข้อเดียว — LonelyWorldException ต้องเพิ่มข้อยกเว้นอื่นๆ ลงในลายเซ็น โดยระบุหลังthrows คำหลัก |
3. จับข้อยกเว้นทั้งหมด
หากเมธอดไม่ส่งข้อยกเว้นไปยังเมธอดการโทร แสดงว่าเมธอดการโทรนั้นมั่นใจเสมอว่าทุกอย่างทำงานได้ดี และจะไม่สามารถดำเนินการใด ๆ เพื่อแก้ไขสถานการณ์พิเศษได้
รหัส | บันทึก |
---|---|
|
ข้อยกเว้นทั้งหมดถูกจับได้ในวิธีนี้ ผู้โทรจะได้มั่นใจว่าทุกอย่างผ่านไปด้วยดี |
3. การตัดคำยกเว้น
ข้อยกเว้น ที่ได้รับการตรวจสอบนั้นดูยอดเยี่ยมในทางทฤษฎี แต่กลายเป็นความยุ่งยากอย่างมากในทางปฏิบัติ
สมมติว่าคุณมีวิธียอดนิยมในโครงการของคุณ มันถูกเรียกจากหลายร้อยแห่งในโปรแกรมของคุณ และคุณตัดสินใจที่จะเพิ่ม ข้อยกเว้น ที่เลือกไว้ ใหม่ เข้าไป และอาจเป็นไปได้ว่า ข้อยกเว้น ที่ได้รับการตรวจสอบ นี้ มีความสำคัญมากและพิเศษมากจนมีเพียงmain()
เมธอดเท่านั้นที่รู้ว่าต้องทำอย่างไรหากถูกจับได้
ซึ่งหมายความว่าคุณจะต้องเพิ่มข้อยกเว้นที่เลือกไว้throws
ในส่วนคำสั่งของทุกวิธีที่เรียกใช้วิธีการยอดนิยมของคุณ รวมทั้งในthrows
อนุประโยคของเมธอดทั้งหลายที่เรียกเมธอดเหล่านั้น. และของเมธอดที่เรียกเมธอดเหล่านั้น
เป็นผลให้throws
ส่วนคำสั่งของครึ่งหนึ่งของวิธีการในโครงการได้รับข้อยกเว้นการตรวจสอบ ใหม่ และแน่นอนว่าโปรเจ็กต์ของคุณอยู่ภายใต้การทดสอบ และตอนนี้การทดสอบจะไม่คอมไพล์ และตอนนี้คุณต้องแก้ไขคำสั่งโยนในการทดสอบของคุณด้วย
จากนั้นรหัสทั้งหมดของคุณ (การเปลี่ยนแปลงทั้งหมดในไฟล์หลายร้อยไฟล์) จะต้องได้รับการตรวจสอบโดยโปรแกรมเมอร์รายอื่น และ ณ จุดนี้เราถามตัวเองว่าทำไมเราถึงทำการเปลี่ยนแปลงมากมายในโครงการ? วัน (s?) ของการทำงานและการทดสอบที่เสียหาย - ทั้งหมดนี้เพื่อเพิ่ม ข้อยกเว้น ที่ตรวจสอบหรือไม่?
และแน่นอนว่ายังคงมีปัญหาเกี่ยวกับการสืบทอดและวิธีการแทนที่ ปัญหาที่มาจาก ข้อยกเว้น ที่ตรวจสอบมีขนาดใหญ่กว่าผลประโยชน์ บรรทัดล่างคือตอนนี้มีเพียงไม่กี่คนที่รักพวกเขาและมีคนไม่กี่คนที่ใช้พวกเขา
อย่างไรก็ตาม ยังมีโค้ดจำนวนมาก (รวมถึงโค้ดไลบรารี Java มาตรฐาน) ที่มีข้อยกเว้นที่ตรวจสอบ เหล่านี้ จะทำอย่างไรกับพวกเขา? เราไม่สามารถเพิกเฉยต่อสิ่งเหล่านี้ได้ และเราไม่รู้ว่าจะจัดการกับมันอย่างไร
โปรแกรมเมอร์ Java เสนอให้ห่อ ข้อยกเว้น ที่ตรวจสอบแล้วในRuntimeException
. กล่าวอีกนัยหนึ่งคือ จับ ข้อยกเว้น ที่ตรวจสอบ ทั้งหมด แล้วสร้าง ข้อยกเว้น ที่ไม่ได้ตรวจสอบ (เช่นRuntimeException
) แล้วโยนทิ้งไปแทน การทำเช่นนั้นมีลักษณะดังนี้:
try
{
// Code where a checked exception might occur
}
catch(Exception exp)
{
throw new RuntimeException(exp);
}
มันไม่ใช่วิธีแก้ปัญหาที่สวยงามนัก แต่ที่นี่ไม่มีอาชญากร: ข้อยกเว้นถูกยัดไว้ในไฟล์RuntimeException
.
หากต้องการ คุณสามารถเรียกคืนจากที่นั่นได้อย่างง่ายดาย ตัวอย่าง:
รหัส | บันทึก |
---|---|
|
รับข้อยกเว้นที่เก็บไว้ใน RuntimeException วัตถุ ตัวแปรcause อาจจะnull กำหนดประเภทของมันและแปลงเป็นประเภทข้อยกเว้น ที่ตรวจสอบ |
4. จับข้อยกเว้นหลายรายการ
โปรแกรมเมอร์เกลียดการทำซ้ำรหัส พวกเขายังมาพร้อมกับหลักการพัฒนาที่สอดคล้องกัน: Don't Repeat Yourself (DRY ) แต่เมื่อจัดการข้อยกเว้น มีโอกาสบ่อยครั้งที่try
บล็อกหลายcatch
บล็อกตามด้วยรหัสเดียวกัน
หรืออาจมี 3 catch
บล็อกที่มีรหัสเดียวกัน และอีก 2 catch
บล็อกที่มีรหัสเหมือนกัน นี่เป็นสถานการณ์มาตรฐานเมื่อโครงการของคุณจัดการกับข้อยกเว้นอย่างมีความรับผิดชอบ
เริ่มต้นด้วยเวอร์ชัน 7 ในภาษา Java เพิ่มความสามารถในการระบุข้อยกเว้นหลายประเภทในcatch
บล็อก เดียว ดูเหมือนว่า:
try
{
// Code where an exception might occur
}
catch (ExceptionType1 | ExceptionType2 | ExceptionType3 name)
{
// Exception handling code
}
คุณสามารถมีบล็อกได้มากเท่าcatch
ที่คุณต้องการ อย่างไรก็ตามcatch
บล็อกเดียวไม่สามารถระบุข้อยกเว้นที่สืบทอดกันได้ กล่าวอีกนัยหนึ่ง คุณไม่สามารถเขียน catch ( Exception
| RuntimeException
e) ได้ เนื่องจากRuntimeException
คลาสสืบทอดException
มา
5. ข้อยกเว้นที่กำหนดเอง
คุณสามารถสร้างคลาสยกเว้นของคุณเองได้ตลอดเวลา คุณเพียงแค่สร้างคลาสที่สืบทอดRuntimeException
คลาส มันจะมีลักษณะดังนี้:
class ClassName extends RuntimeException
{
}
เราจะพูดถึงรายละเอียดเมื่อคุณเรียนรู้ OOP, การสืบทอด, ตัวสร้าง และการแทนที่เมธอด
อย่างไรก็ตาม แม้ว่าคุณจะมีเพียงคลาสง่ายๆ แบบนี้ (ไม่มีโค้ดทั้งหมด) คุณก็ยังสามารถโยนข้อยกเว้นตามคลาสนี้ได้:
รหัส | บันทึก |
---|---|
|
โยนเครื่องหมาย MyException . |
ใน ภารกิจ Java Multithreadingเราจะเจาะลึกการทำงานกับข้อยกเว้นที่กำหนดเองของเรา
GO TO FULL VERSION