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. หากมีการส่งผ่านอาร์กิวเมนต์ที่ไม่ถูกต้องไปยังเมธอด มันจะโยนไฟล์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

ตัวอย่าง:

ตรวจสอบข้อยกเว้น ข้อยกเว้นที่ไม่ได้ตรวจสอบ
public void calculate(int n) throws Exception
{
   if (n == 0)
      throw new Exception("n is null!");
}
public void calculate(n)
{
   if (n == 0)
      throw new RuntimeException("n is null!");
}

ในตัวอย่างด้านขวา โค้ดของเราแสดง ข้อยกเว้น ที่ไม่ได้ตรวจสอบ — ไม่จำเป็นต้องดำเนินการใดๆ เพิ่มเติม ในตัวอย่างทางด้านซ้าย เมธอดจะส่ง ข้อยกเว้น ที่ตรวจสอบดังนั้น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ส่วนคำสั่งสำหรับวิธีการของคุณ

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

ตัวอย่าง:

ลองนึกภาพว่าเรากำลังเขียนวิธีการสร้างโลกที่มีมนุษย์อาศัยอยู่ จำนวนคนเริ่มต้นจะถูกส่งผ่านเป็นอาร์กิวเมนต์ เราจึงต้องเพิ่มข้อยกเว้นหากมีคนน้อยเกินไป

สร้างโลก บันทึก
public void createWorld(int n) throws EmptyWorldException, LonelyWorldException
{
   if (n == 0)
      throw new EmptyWorldException("There are no people!");
   if (n == 1)
      throw new LonelyWorldException ("There aren't enough people!");
   System.out.println("A wonderful world was created. Population: " + n);
}
เมธอดนี้อาจมี ข้อยกเว้น ที่ตรวจสอบแล้ว สอง รายการ:

  • EmptyWorldException
  • ข้อยกเว้นโลกเดียวดาย

การเรียกใช้เมธอดนี้สามารถจัดการได้ 3 วิธี:

1. อย่าจับข้อยกเว้นใด ๆ

สิ่งนี้มักทำเมื่อวิธีการนี้ไม่ทราบวิธีจัดการกับสถานการณ์อย่างเหมาะสม

รหัส บันทึก
public void createPopulatedWorld(int population)
throws EmptyWorldException, LonelyWorldException
{
   createWorld(population);
}
เมธอดการโทรไม่จับข้อยกเว้นและต้องแจ้งให้ผู้อื่นทราบ: มันเพิ่มเข้าไปในthrowsอนุประโยค ของมันเอง

2. จับข้อยกเว้นบางประการ

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

รหัส บันทึก
public void createNonEmptyWorld(int population)
throws EmptyWorldException
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
}
ผู้โทรจับข้อยกเว้นที่เลือกไว้เพียงข้อเดียวLonelyWorldExceptionต้องเพิ่มข้อยกเว้นอื่นๆ ลงในลายเซ็น โดยระบุหลังthrowsคำหลัก

3. จับข้อยกเว้นทั้งหมด

หากเมธอดไม่ส่งข้อยกเว้นไปยังเมธอดการโทร แสดงว่าเมธอดการโทรนั้นมั่นใจเสมอว่าทุกอย่างทำงานได้ดี และจะไม่สามารถดำเนินการใด ๆ เพื่อแก้ไขสถานการณ์พิเศษได้

รหัส บันทึก
public void createAnyWorld(int population)
{
   try
   {
      createWorld(population);
   }
   catch (LonelyWorldException e)
   {
      e.printStackTrace();
   }
   catch (EmptyWorldException e)
   {
      e.printStackTrace();
   }
}
ข้อยกเว้นทั้งหมดถูกจับได้ในวิธีนี้ ผู้โทรจะได้มั่นใจว่าทุกอย่างผ่านไปด้วยดี


3. จับข้อยกเว้นหลายรายการ

โปรแกรมเมอร์เกลียดการทำซ้ำรหัส พวกเขายังคิดหลักการพัฒนาที่สอดคล้องกัน — DRY : Don't Repeat Yourself แต่เมื่อจัดการกับข้อยกเว้น มีโอกาสบ่อยครั้งที่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| RuntimeExceptione) ได้ เนื่องจากRuntimeExceptionคลาสสืบทอดExceptionมา