Java - ข้อยกเว้น
ข้อยกเว้น (หรือเหตุการณ์พิเศษ) คือปัญหาที่เกิดขึ้นระหว่างการทำงานของโปรแกรม เมื่อException เกิดขั้นตอนปกติของโปรแกรมหยุดชะงักและโปรแกรม / แอปพลิเคชันหยุดทำงานอย่างผิดปกติซึ่งไม่แนะนำดังนั้นจึงต้องจัดการข้อยกเว้นเหล่านี้
ข้อยกเว้นอาจเกิดขึ้นได้จากหลายสาเหตุ ต่อไปนี้เป็นสถานการณ์บางอย่างที่มีข้อยกเว้นเกิดขึ้น
ผู้ใช้ป้อนข้อมูลที่ไม่ถูกต้อง
ไม่พบไฟล์ที่ต้องเปิด
การเชื่อมต่อเครือข่ายขาดหายไประหว่างการสื่อสารหรือ JVM หน่วยความจำหมด
ข้อยกเว้นเหล่านี้บางส่วนเกิดจากข้อผิดพลาดของผู้ใช้ข้อผิดพลาดของโปรแกรมเมอร์และอื่น ๆ โดยทรัพยากรทางกายภาพที่ล้มเหลวในบางลักษณะ
จากสิ่งเหล่านี้เรามีข้อยกเว้นสามประเภท คุณต้องเข้าใจพวกเขาเพื่อทราบว่าการจัดการข้อยกเว้นทำงานอย่างไรใน Java
Checked exceptions- ข้อยกเว้นที่ตรวจสอบแล้วคือข้อยกเว้นที่คอมไพเลอร์ตรวจสอบ (แจ้งเตือน) ณ เวลาคอมไพล์ซึ่งเรียกอีกอย่างว่าข้อยกเว้นเวลาคอมไพล์ ข้อยกเว้นเหล่านี้ไม่สามารถละเลยได้โปรแกรมเมอร์ควรดูแล (จัดการ) ข้อยกเว้นเหล่านี้
ตัวอย่างเช่นถ้าคุณใช้ FileReaderคลาสในโปรแกรมของคุณเพื่ออ่านข้อมูลจากไฟล์หากไม่มีไฟล์ที่ระบุในคอนสตรัคเตอร์FileNotFoundExceptionจะเกิดขึ้นและคอมไพเลอร์จะแจ้งให้โปรแกรมเมอร์จัดการกับข้อยกเว้น
ตัวอย่าง
import java.io.File;
import java.io.FileReader;
public class FilenotFound_Demo {
public static void main(String args[]) {
File file = new File("E://file.txt");
FileReader fr = new FileReader(file);
}
}
หากคุณพยายามรวบรวมโปรแกรมข้างต้นคุณจะได้รับข้อยกเว้นดังต่อไปนี้
เอาต์พุต
C:\>javac FilenotFound_Demo.java
FilenotFound_Demo.java:8: error: unreported exception FileNotFoundException; must be caught or declared to be thrown
FileReader fr = new FileReader(file);
^
1 error
Note - ตั้งแต่วิธีการ read() และ close() ของคลาส FileReader พ่น IOException คุณสามารถสังเกตได้ว่าคอมไพลเลอร์แจ้งให้จัดการ IOException พร้อมกับ FileNotFoundException
Unchecked exceptions- ข้อยกเว้นที่ไม่ได้ตรวจสอบคือข้อยกเว้นที่เกิดขึ้นในขณะดำเนินการ สิ่งเหล่านี้เรียกอีกอย่างว่าRuntime Exceptions. ซึ่งรวมถึงข้อบกพร่องในการเขียนโปรแกรมเช่นข้อผิดพลาดทางตรรกะหรือการใช้ API อย่างไม่เหมาะสม ข้อยกเว้นรันไทม์จะถูกละเว้นในช่วงเวลาของการคอมไพล์
ตัวอย่างเช่นถ้าคุณได้ประกาศอาร์เรย์ของขนาด 5 ในโปรแกรมของคุณและพยายามที่จะเรียก 6 THองค์ประกอบของอาร์เรย์แล้วArrayIndexOutOfBoundsExceptionexceptionเกิดขึ้น
ตัวอย่าง
public class Unchecked_Demo {
public static void main(String args[]) {
int num[] = {1, 2, 3, 4};
System.out.println(num[5]);
}
}
หากคุณคอมไพล์และรันโปรแกรมข้างต้นคุณจะได้รับข้อยกเว้นดังต่อไปนี้
เอาต์พุต
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
at Exceptions.Unchecked_Demo.main(Unchecked_Demo.java:8)
Errors- สิ่งเหล่านี้ไม่ใช่ข้อยกเว้น แต่เป็นปัญหาที่เกิดขึ้นนอกเหนือการควบคุมของผู้ใช้หรือโปรแกรมเมอร์ โดยทั่วไปข้อผิดพลาดจะถูกละเว้นในโค้ดของคุณเนื่องจากคุณแทบไม่สามารถทำอะไรเกี่ยวกับข้อผิดพลาดได้ ตัวอย่างเช่นหากเกิดสแต็กล้นจะเกิดข้อผิดพลาด นอกจากนี้ยังถูกละเว้นในช่วงเวลาของการรวบรวม
ลำดับชั้นของข้อยกเว้น
คลาสข้อยกเว้นทั้งหมดเป็นประเภทย่อยของคลาส java.lang.Exception คลาสข้อยกเว้นเป็นคลาสย่อยของคลาส Throwable นอกเหนือจากคลาสข้อยกเว้นยังมีคลาสย่อยอื่นที่เรียกว่า Error ซึ่งได้มาจากคลาส Throwable
ข้อผิดพลาดเป็นเงื่อนไขผิดปกติที่เกิดขึ้นในกรณีที่เกิดความล้มเหลวอย่างรุนแรงสิ่งเหล่านี้ไม่ได้รับการจัดการโดยโปรแกรม Java ข้อผิดพลาดถูกสร้างขึ้นเพื่อระบุข้อผิดพลาดที่สร้างขึ้นโดยสภาพแวดล้อมรันไทม์ ตัวอย่าง: JVM ไม่มีหน่วยความจำ โดยปกติโปรแกรมไม่สามารถกู้คืนจากข้อผิดพลาด
คลาส Exception มีคลาสย่อยหลักสองคลาส: คลาส IOException และคลาส RuntimeException
ต่อไปนี้เป็นรายการที่พบบ่อยที่สุดตรวจสอบและไม่ได้ตรวจสอบJava ในตัวของข้อยกเว้น
วิธีการยกเว้น
ต่อไปนี้เป็นรายการวิธีการสำคัญที่มีอยู่ในคลาส Throwable
ซีเนียร์ | วิธีการและคำอธิบาย |
---|---|
1 | public String getMessage() ส่งคืนข้อความโดยละเอียดเกี่ยวกับข้อยกเว้นที่เกิดขึ้น ข้อความนี้เริ่มต้นในตัวสร้าง Throwable |
2 | public Throwable getCause() ส่งคืนสาเหตุของข้อยกเว้นที่แสดงโดยวัตถุ Throwable |
3 | public String toString() ส่งคืนชื่อของคลาสที่เชื่อมต่อกับผลลัพธ์ของ getMessage () |
4 | public void printStackTrace() พิมพ์ผลลัพธ์ของ toString () พร้อมกับการติดตามสแต็กไปยัง System.err สตรีมเอาต์พุตข้อผิดพลาด |
5 | public StackTraceElement [] getStackTrace() ส่งคืนอาร์เรย์ที่มีแต่ละองค์ประกอบบนการติดตามสแต็ก องค์ประกอบที่ดัชนี 0 แสดงถึงด้านบนสุดของ call stack และองค์ประกอบสุดท้ายในอาร์เรย์แสดงถึงวิธีการที่ด้านล่างของ call stack |
6 | public Throwable fillInStackTrace() เติมการติดตามสแต็กของอ็อบเจ็กต์ Throwable นี้ด้วยการติดตามสแต็กปัจจุบันโดยเพิ่มข้อมูลก่อนหน้านี้ในการติดตามสแต็ก |
การจับข้อยกเว้น
เมธอดจับข้อยกเว้นโดยใช้การรวมกันของ try และ catchคำหลัก บล็อก try / catch ถูกวางไว้รอบ ๆ รหัสที่อาจสร้างข้อยกเว้น โค้ดภายในบล็อก try / catch เรียกว่าโค้ดที่มีการป้องกันและไวยากรณ์สำหรับการใช้ try / catch มีลักษณะดังนี้ -
ไวยากรณ์
try {
// Protected code
} catch (ExceptionName e1) {
// Catch block
}
รหัสที่มีแนวโน้มที่จะเกิดข้อยกเว้นจะถูกวางไว้ในบล็อกลอง เมื่อเกิดข้อยกเว้นข้อยกเว้นที่เกิดขึ้นจะถูกจัดการโดย catch block ที่เกี่ยวข้อง การบล็อกการลองทุกครั้งควรตามด้วยบล็อกจับหรือบล็อกในที่สุด
คำสั่งจับเกี่ยวข้องกับการประกาศประเภทของข้อยกเว้นที่คุณพยายามจับ หากมีข้อยกเว้นเกิดขึ้นในรหัสที่ได้รับการป้องกันบล็อก catch (หรือบล็อก) ที่ตามมาจะถูกตรวจสอบ หากชนิดของข้อยกเว้นที่เกิดขึ้นแสดงอยู่ในบล็อก catch ข้อยกเว้นจะถูกส่งผ่านไปยังบล็อก catch เมื่ออาร์กิวเมนต์ถูกส่งไปยังพารามิเตอร์เมธอด
ตัวอย่าง
ต่อไปนี้คืออาร์เรย์ที่ประกาศด้วย 2 องค์ประกอบ จากนั้นรหัสจะพยายามเข้าถึงองค์ประกอบ3 rdของอาร์เรย์ซึ่งทำให้เกิดข้อยกเว้น
// File Name : ExcepTest.java
import java.io.*;
public class ExcepTest {
public static void main(String args[]) {
try {
int a[] = new int[2];
System.out.println("Access element three :" + a[3]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Exception thrown :" + e);
}
System.out.println("Out of the block");
}
}
สิ่งนี้จะให้ผลลัพธ์ดังต่อไปนี้ -
เอาต์พุต
Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3
Out of the block
หลาย Catch Blocks
บล็อกลองสามารถตามด้วยบล็อกจับหลาย ๆ ไวยากรณ์สำหรับบล็อกการจับหลายรายการมีลักษณะดังต่อไปนี้ -
ไวยากรณ์
try {
// Protected code
} catch (ExceptionType1 e1) {
// Catch block
} catch (ExceptionType2 e2) {
// Catch block
} catch (ExceptionType3 e3) {
// Catch block
}
ข้อความก่อนหน้านี้แสดงให้เห็นถึงการจับสามบล็อก แต่คุณสามารถมีจำนวนเท่าใดก็ได้หลังจากลองครั้งเดียว หากมีข้อยกเว้นเกิดขึ้นในรหัสที่ได้รับการป้องกันข้อยกเว้นจะถูกส่งไปยังบล็อกแรกในรายการ หากประเภทข้อมูลของข้อยกเว้นที่ส่งตรงกับ ExceptionType1 จะถูกจับที่นั่น ถ้าไม่เช่นนั้นข้อยกเว้นจะส่งผ่านไปยังคำสั่ง catch ที่สอง สิ่งนี้จะดำเนินต่อไปจนกว่าข้อยกเว้นจะถูกจับหรือตกผ่านการจับทั้งหมดซึ่งในกรณีนี้เมธอดปัจจุบันจะหยุดการดำเนินการและข้อยกเว้นจะถูกโยนลงไปที่เมธอดก่อนหน้าบน call stack
ตัวอย่าง
นี่คือส่วนของโค้ดที่แสดงวิธีใช้คำสั่ง try / catch หลายรายการ
try {
file = new FileInputStream(fileName);
x = (byte) file.read();
} catch (IOException i) {
i.printStackTrace();
return -1;
} catch (FileNotFoundException f) // Not valid! {
f.printStackTrace();
return -1;
}
การจับข้อยกเว้นหลายประเภท
ตั้งแต่ Java 7 คุณสามารถจัดการข้อยกเว้นได้มากกว่าหนึ่งรายการโดยใช้บล็อกเดียวคุณลักษณะนี้ช่วยลดความซับซ้อนของโค้ด นี่คือวิธีที่คุณจะทำ -
catch (IOException|FileNotFoundException ex) {
logger.log(ex);
throw ex;
คำหลักโยน / โยน
หากเมธอดไม่จัดการกับข้อยกเว้นที่ถูกตรวจสอบเมธอดนั้นจะต้องประกาศโดยใช้ throwsคำสำคัญ. คีย์เวิร์ดพ่นจะปรากฏที่ส่วนท้ายของลายเซ็นของเมธอด
คุณสามารถโยนข้อยกเว้นไม่ว่าจะเป็นการสร้างอินสแตนซ์ใหม่หรือข้อยกเว้นที่คุณเพิ่งจับได้โดยใช้ไฟล์ throw คำสำคัญ.
พยายามทำความเข้าใจความแตกต่างระหว่างการโยนและการโยนคำหลักการโยนใช้เพื่อเลื่อนการจัดการข้อยกเว้นที่ตรวจสอบแล้วและการโยนถูกใช้เพื่อเรียกใช้ข้อยกเว้นอย่างชัดเจน
วิธีการต่อไปนี้ประกาศว่าจะพ่น RemoteException -
ตัวอย่าง
import java.io.*;
public class className {
public void deposit(double amount) throws RemoteException {
// Method implementation
throw new RemoteException();
}
// Remainder of class definition
}
เมธอดสามารถประกาศได้ว่ามีข้อยกเว้นมากกว่าหนึ่งข้อซึ่งในกรณีนี้จะมีการประกาศข้อยกเว้นในรายการโดยคั่นด้วยเครื่องหมายจุลภาค ตัวอย่างเช่นวิธีการต่อไปนี้ประกาศว่าจะพ่น RemoteException และ InsufficientFundsException -
ตัวอย่าง
import java.io.*;
public class className {
public void withdraw(double amount) throws RemoteException,
InsufficientFundsException {
// Method implementation
}
// Remainder of class definition
}
สุดท้ายบล็อก
บล็อกสุดท้ายตามด้วย try block หรือ catch block ในที่สุดบล็อกโค้ดจะดำเนินการเสมอโดยไม่คำนึงถึงการเกิดข้อยกเว้น
การใช้บล็อกในที่สุดช่วยให้คุณสามารถเรียกใช้คำสั่งประเภทการล้างข้อมูลที่คุณต้องการดำเนินการได้ไม่ว่าจะเกิดอะไรขึ้นในรหัสที่ได้รับการป้องกัน
ในที่สุดบล็อกจะปรากฏที่ส่วนท้ายของบล็อกจับและมีไวยากรณ์ต่อไปนี้ -
ไวยากรณ์
try {
// Protected code
} catch (ExceptionType1 e1) {
// Catch block
} catch (ExceptionType2 e2) {
// Catch block
} catch (ExceptionType3 e3) {
// Catch block
}finally {
// The finally block always executes.
}
ตัวอย่าง
public class ExcepTest {
public static void main(String args[]) {
int a[] = new int[2];
try {
System.out.println("Access element three :" + a[3]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Exception thrown :" + e);
}finally {
a[0] = 6;
System.out.println("First element value: " + a[0]);
System.out.println("The finally statement is executed");
}
}
}
สิ่งนี้จะให้ผลลัพธ์ดังต่อไปนี้ -
เอาต์พุต
Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3
First element value: 6
The finally statement is executed
หมายเหตุต่อไปนี้ -
ประโยค catch ไม่สามารถอยู่ได้หากไม่มีคำสั่ง try
ไม่บังคับที่จะต้องมีประโยคสุดท้ายเมื่อใดก็ตามที่มีการบล็อก try / catch
ไม่สามารถนำเสนอ try block ได้หากไม่มีประโยค catch หรือประโยคสุดท้าย
ไม่สามารถแสดงรหัสใด ๆ ระหว่างการลองจับสุดท้ายบล็อก
ลองใช้ทรัพยากร
โดยทั่วไปเมื่อเราใช้ทรัพยากรใด ๆ เช่นสตรีมการเชื่อมต่อ ฯลฯ เราจะต้องปิดอย่างชัดเจนโดยใช้การบล็อกในที่สุด ในโปรแกรมต่อไปนี้เรากำลังอ่านข้อมูลจากไฟล์โดยใช้FileReader และเรากำลังปิดมันโดยใช้การบล็อกในที่สุด
ตัวอย่าง
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class ReadData_Demo {
public static void main(String args[]) {
FileReader fr = null;
try {
File file = new File("file.txt");
fr = new FileReader(file); char [] a = new char[50];
fr.read(a); // reads the content to the array
for(char c : a)
System.out.print(c); // prints the characters one by one
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
fr.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
try-with-resourcesหรือเรียกอีกอย่างว่า automatic resource managementเป็นกลไกการจัดการข้อยกเว้นใหม่ที่นำมาใช้ใน Java 7 ซึ่งจะปิดทรัพยากรที่ใช้ภายในบล็อก try catch โดยอัตโนมัติ
ในการใช้คำสั่งนี้คุณเพียงแค่ต้องประกาศทรัพยากรที่ต้องการภายในวงเล็บและทรัพยากรที่สร้างขึ้นจะถูกปิดโดยอัตโนมัติเมื่อสิ้นสุดบล็อก ต่อไปนี้เป็นไวยากรณ์ของคำสั่ง try-with-resources
ไวยากรณ์
try(FileReader fr = new FileReader("file path")) {
// use the resource
} catch () {
// body of catch
}
}
ต่อไปนี้เป็นโปรแกรมที่อ่านข้อมูลในไฟล์โดยใช้คำสั่ง try-with-resources
ตัวอย่าง
import java.io.FileReader;
import java.io.IOException;
public class Try_withDemo {
public static void main(String args[]) {
try(FileReader fr = new FileReader("E://file.txt")) {
char [] a = new char[50];
fr.read(a); // reads the contentto the array
for(char c : a)
System.out.print(c); // prints the characters one by one
} catch (IOException e) {
e.printStackTrace();
}
}
}
ควรคำนึงถึงประเด็นต่อไปนี้ในขณะที่ทำงานกับคำสั่ง try-with-resources
ในการใช้คลาสที่มีคำสั่ง try-with-resources ควรใช้ AutoCloseable อินเตอร์เฟซและ close() วิธีการของมันจะถูกเรียกโดยอัตโนมัติเมื่อรันไทม์
คุณสามารถประกาศมากกว่าหนึ่งคลาสในคำสั่ง try-with-resources
ในขณะที่คุณประกาศหลายคลาสในบล็อก try ของคำสั่ง try-with-resources คลาสเหล่านี้จะปิดตามลำดับย้อนกลับ
ยกเว้นการประกาศทรัพยากรภายในวงเล็บทุกอย่างจะเหมือนกับบล็อก try / catch ปกติของบล็อก try
ทรัพยากรที่ประกาศในการทดลองใช้จะได้รับการสร้างอินสแตนซ์ก่อนที่จะเริ่มบล็อกการพยายาม
ทรัพยากรที่ประกาศในบล็อกลองถูกประกาศโดยปริยายว่าเป็นขั้นสุดท้าย
ข้อยกเว้นที่ผู้ใช้กำหนด
คุณสามารถสร้างข้อยกเว้นของคุณเองใน Java โปรดคำนึงถึงประเด็นต่อไปนี้เมื่อเขียนคลาสข้อยกเว้นของคุณเอง -
ข้อยกเว้นทั้งหมดต้องเป็นลูกของ Throwable
หากคุณต้องการเขียนข้อยกเว้นที่ตรวจสอบแล้วซึ่งบังคับใช้โดยอัตโนมัติโดยกฎ Handle หรือ Declare คุณต้องขยายคลาส Exception
หากคุณต้องการเขียนข้อยกเว้นรันไทม์คุณต้องขยายคลาส RuntimeException
เราสามารถกำหนดคลาส Exception ของเราเองได้ดังนี้ -
class MyException extends Exception {
}
คุณเพียงแค่ต้องขยายที่กำหนดไว้ล่วงหน้า Exceptionคลาสเพื่อสร้าง Exception ของคุณเอง สิ่งเหล่านี้ถือเป็นการตรวจสอบข้อยกเว้น ดังต่อไปนี้InsufficientFundsExceptionคลาสเป็นข้อยกเว้นที่ผู้ใช้กำหนดเองซึ่งขยายคลาส Exception ทำให้เป็นข้อยกเว้นที่ถูกตรวจสอบ คลาสข้อยกเว้นก็เหมือนกับคลาสอื่น ๆ ที่มีฟิลด์และวิธีการที่เป็นประโยชน์
ตัวอย่าง
// File Name InsufficientFundsException.java
import java.io.*;
public class InsufficientFundsException extends Exception {
private double amount;
public InsufficientFundsException(double amount) {
this.amount = amount;
}
public double getAmount() {
return amount;
}
}
เพื่อแสดงให้เห็นโดยใช้ข้อยกเว้นที่ผู้ใช้กำหนดเองคลาส CheckingAccount ต่อไปนี้มีวิธีการถอน () ที่พ่น InsufficientFundsException
// File Name CheckingAccount.java
import java.io.*;
public class CheckingAccount {
private double balance;
private int number;
public CheckingAccount(int number) {
this.number = number;
}
public void deposit(double amount) {
balance += amount;
}
public void withdraw(double amount) throws InsufficientFundsException {
if(amount <= balance) {
balance -= amount;
}else {
double needs = amount - balance;
throw new InsufficientFundsException(needs);
}
}
public double getBalance() {
return balance;
}
public int getNumber() {
return number;
}
}
โปรแกรม BankDemo ต่อไปนี้แสดงให้เห็นถึงการเรียกใช้วิธีการฝาก () และถอน () ของ CheckingAccount
// File Name BankDemo.java
public class BankDemo {
public static void main(String [] args) {
CheckingAccount c = new CheckingAccount(101);
System.out.println("Depositing $500...");
c.deposit(500.00);
try {
System.out.println("\nWithdrawing $100...");
c.withdraw(100.00);
System.out.println("\nWithdrawing $600...");
c.withdraw(600.00);
} catch (InsufficientFundsException e) {
System.out.println("Sorry, but you are short $" + e.getAmount());
e.printStackTrace();
}
}
}
รวบรวมไฟล์ทั้งสามไฟล์ข้างต้นและเรียกใช้ BankDemo สิ่งนี้จะให้ผลลัพธ์ดังต่อไปนี้ -
เอาต์พุต
Depositing $500...
Withdrawing $100...
Withdrawing $600...
Sorry, but you are short $200.0
InsufficientFundsException
at CheckingAccount.withdraw(CheckingAccount.java:25)
at BankDemo.main(BankDemo.java:13)
ข้อยกเว้นทั่วไป
ใน Java สามารถกำหนดส่วนจัดเลี้ยงของข้อยกเว้นและข้อผิดพลาดได้สองรายการ
JVM Exceptions- นี่คือข้อยกเว้น / ข้อผิดพลาดที่ JVM โยนมาโดยเฉพาะหรือมีเหตุผล ตัวอย่าง: NullPointerException, ArrayIndexOutOfBoundsException, ClassCastException
Programmatic Exceptions- ข้อยกเว้นเหล่านี้ถูกโยนทิ้งอย่างชัดเจนโดยแอปพลิเคชันหรือโปรแกรมเมอร์ API ตัวอย่าง: IllegalArgumentException, IllegalStateException