Thứ Hai, 9 tháng 7, 2018

Java - Ngoại lệ

Một ngoại lệ (hoặc sự kiện đặc biệt) là một vấn đề nảy sinh trong quá trình thực thi chương trình. Khi một ngoại lệ xảy ra dòng chảy bình thường của chương trình bị gián đoạn và chương trình / ứng dụng chấm dứt bất thường, mà không được khuyến khích, do đó, những ngoại lệ này sẽ được xử lý.

Một ngoại lệ có thể xảy ra vì nhiều lý do khác nhau. Sau đây là một số tình huống xảy ra ngoại lệ.

Người dùng đã nhập dữ liệu không hợp lệ.

Không thể tìm thấy tệp cần mở.

Một kết nối mạng đã bị mất ở giữa các liên lạc hoặc JVM đã hết bộ nhớ.

Một số ngoại lệ này do lỗi người dùng gây ra, một số ngoại lệ khác do lỗi lập trình viên và các lỗi khác do tài nguyên vật lý bị lỗi theo một cách nào đó.

Dựa trên những điều này, chúng tôi có ba loại ngoại lệ. Bạn cần phải hiểu họ để biết cách xử lý ngoại lệ hoạt động trong lập trình Java.

Ngoại lệ được kiểm tra - Ngoại lệ được kiểm tra là ngoại lệ xảy ra tại thời gian biên dịch, các trường hợp này cũng được gọi là ngoại lệ thời gian biên dịch. Những ngoại lệ này không thể đơn giản được bỏ qua tại thời điểm biên dịch, lập trình viên nên xử lý (xử lý) những ngoại lệ này.

Ví dụ, nếu bạn sử dụng lớp FileReader trong chương trình của bạn để đọc dữ liệu từ một tệp, nếu tệp được chỉ định trong hàm tạo của nó không tồn tại, thì một FileNotFoundException xảy ra, và trình biên dịch sẽ nhắc người lập trình xử lý ngoại lệ.

Thí dụ

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); 
   }
}

Nếu bạn cố gắng biên dịch chương trình trên, bạn sẽ nhận được các ngoại lệ sau.

Đầu ra

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

Lưu ý - Vì phương thức read () và close () của lớp FileReader ném IOException, bạn có thể quan sát thấy trình biên dịch thông báo để xử lý IOException, cùng với FileNotFoundException.

Các ngoại lệ không được kiểm soát - Một ngoại lệ không được kiểm soát là một ngoại lệ xảy ra tại thời điểm thực thi. Chúng cũng được gọi là Runtime Exceptions . Chúng bao gồm các lỗi lập trình, chẳng hạn như lỗi logic hoặc sử dụng API không đúng cách. Các ngoại lệ thời gian chạy được bỏ qua tại thời điểm biên dịch.

Ví dụ, nếu bạn đã khai báo một mảng có kích thước 5 trong chương trình của bạn, và cố gắng gọi phần tử thứ 6 của mảng thì một Array Index Out Of Bounds Exceptionexception xảy ra.

Thí dụ

public class Unchecked_Demo {
   
   public static void main(String args[]) {
      int num[] = {1, 2, 3, 4};
      System.out.println(num[5]);
   }
}
Nếu bạn biên dịch và thực hiện chương trình trên, bạn sẽ nhận được ngoại lệ sau.

Đầu ra

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
 at Exceptions.Unchecked_Demo.main(Unchecked_Demo.java:8)
Lỗi - Đây không phải là ngoại lệ, những vấn đề phát sinh ngoài sự kiểm soát của người dùng hoặc lập trình viên. Lỗi thường bị bỏ qua trong mã của bạn vì bạn hiếm khi có thể làm bất kỳ điều gì về lỗi. Ví dụ, nếu một tràn ngăn xếp xảy ra, một lỗi sẽ phát sinh. Họ cũng bị bỏ qua tại thời điểm biên dịch.

Phân cấp ngoại lệ

Tất cả các lớp ngoại lệ là các kiểu con của lớp java.lang.Exception. Lớp ngoại lệ là một lớp con của lớp Throwable. Khác với lớp ngoại lệ, có một lớp con khác được gọi là Lỗi có nguồn gốc từ lớp Throwable.

Lỗi là những điều kiện bất thường xảy ra trong trường hợp thất bại nghiêm trọng, những điều này không được xử lý bởi các chương trình Java. Lỗi được tạo ra để cho biết lỗi do môi trường thời gian chạy tạo ra. Ví dụ: JVM hết bộ nhớ. Thông thường, các chương trình không thể phục hồi từ lỗi.

Lớp Exception có hai lớp con chính: lớp IOException và lớp Runtime Exception.

NIIT-ICT
ảnh minh họa

Sau đây là danh sách các trường hợp ngoại lệ tích hợp được kiểm tra và kiểm tra phổ biến nhất của Java .

Phương pháp ngoại lệ

Sau đây là danh sách các phương thức quan trọng có sẵn trong lớp Throwable.

Sr.No.Phương thức & Mô tả
1public String getMessage ()

Trả về một thông báo chi tiết về ngoại lệ đã xảy ra. Thông báo này được khởi tạo trong hàm tạo Throwable.
2công khai Throwable getCause ()

Trả về nguyên nhân của ngoại lệ như được đại diện bởi một đối tượng Throwable.
3công khai String toString ()

Trả về tên của lớp được nối với kết quả của getMessage ().
4public void printStackTrace ()

In kết quả của toString () cùng với dấu vết ngăn xếp tới System.err, luồng đầu ra lỗi.
5công khai StackTraceElement [] getStackTrace ()

Trả về một mảng chứa mỗi phần tử trên dấu vết ngăn xếp. Phần tử ở chỉ mục 0 biểu thị phần đầu của ngăn xếp cuộc gọi và phần tử cuối cùng trong mảng đại diện cho phương thức ở cuối ngăn xếp cuộc gọi.
6công khai FillInStackTrace ()

Điền vào dấu vết ngăn xếp của đối tượng Throwable này với dấu vết ngăn xếp hiện tại, thêm vào bất kỳ thông tin nào trước đó trong dấu vết ngăn xếp.

Bắt ngoại lệ

Phương thức bắt một ngoại lệ bằng cách sử dụng kết hợp từ khóa thử và bắt . Một khối try / catch được đặt xung quanh mã có thể tạo ra một ngoại lệ. Mã trong một khối try / catch được gọi là mã được bảo vệ và cú pháp để sử dụng try / catch trông giống như sau:

Cú pháp

try {
   // Protected code
} catch (ExceptionName e1) {
   // Catch block
}

Mã dễ bị ngoại lệ được đặt trong khối thử. Khi một ngoại lệ xảy ra, ngoại lệ đó xảy ra được xử lý bởi khối catch liên kết với nó. Mỗi khối thử phải được theo dõi ngay lập tức bằng khối catch hoặc cuối cùng là chặn.

Một câu lệnh khai thác liên quan đến việc khai báo kiểu ngoại lệ mà bạn đang cố gắng nắm bắt. Nếu một ngoại lệ xảy ra trong mã được bảo vệ, khối catch (hoặc khối) theo sau phép thử được chọn. Nếu loại ngoại lệ xảy ra được liệt kê trong một khối catch, ngoại lệ được chuyển đến khối catch nhiều như một đối số được chuyển vào một tham số phương thức.

Thí dụ

Sau đây là một mảng được khai báo với 2 phần tử. Sau đó, mã cố gắng truy cập phần tử thứ 3 của mảng mà ném một ngoại lệ.
// 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");
   }
}
Điều này sẽ tạo ra kết quả sau

Đầu ra

Exception thrown  :java.lang.ArrayIndexOutOfBoundsException: 3
Out of the block

Nhiều Catch Blocks

Một khối thử có thể được theo sau bởi nhiều khối catch. Cú pháp cho nhiều khối catch trông giống như sau:

Cú pháp

try {
   // Protected code
} catch (ExceptionType1 e1) {
   // Catch block
} catch (ExceptionType2 e2) {
   // Catch block
} catch (ExceptionType3 e3) {
   // Catch block
}

Các báo cáo trước đây trình bày ba khối catch, nhưng bạn có thể có bất kỳ số nào trong số chúng sau một lần thử. Nếu một ngoại lệ xảy ra trong mã được bảo vệ, ngoại lệ sẽ được ném vào khối catch đầu tiên trong danh sách.

Nếu kiểu dữ liệu của ngoại lệ được ném khớp với ExceptionType1, nó sẽ bị bắt ở đó. Nếu không, ngoại lệ sẽ chuyển xuống câu lệnh bắt thứ hai. Điều này tiếp tục cho đến khi ngoại lệ hoặc là bị bắt hoặc rơi qua tất cả các bắt, trong trường hợp đó phương thức hiện tại dừng thực hiện và ngoại lệ được ném xuống phương thức trước đó trên ngăn xếp cuộc gọi.

Thí dụ

Đây là đoạn mã hiển thị cách sử dụng nhiều câu lệnh 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;
}

Nắm bắt nhiều loại ngoại lệ

Java 7, bạn có thể xử lý nhiều hơn một ngoại lệ bằng cách sử dụng một khối catch duy nhất, tính năng này đơn giản hóa mã. Đây là cách bạn sẽ làm điều đó 

catch (IOException|FileNotFoundException ex) {
   logger.log(ex);
   throw ex;

Các ném / ném từ khóa

Nếu một phương thức không xử lý một ngoại lệ đã kiểm tra, phương thức phải khai báo nó bằng cách sử dụng từ khóa ném . Từ khóa ném xuất hiện ở cuối chữ ký của phương thức.

Bạn có thể ném một ngoại lệ, hoặc là một ngoại lệ mới hoặc một ngoại lệ mà bạn vừa mới bắt được, bằng cách sử dụng từ khóa throw .

Cố gắng hiểu sự khác biệt giữa ném và ném từ khóa, ném được sử dụng để trì hoãn việc xử lý của một ngoại lệ kiểm tra và ném được sử dụng để gọi một ngoại lệ một cách rõ ràng.

Phương thức sau tuyên bố rằng nó ném một RemoteException -

Thí dụ
import java.io.*;
public class className {

   public void deposit(double amount) throws RemoteException {
      // Method implementation
      throw new RemoteException();
   }
   // Remainder of class definition
}


Một phương thức có thể khai báo rằng nó ném nhiều hơn một ngoại lệ, trong trường hợp đó các ngoại lệ được khai báo trong một danh sách được phân tách bằng dấu phẩy.

Ví dụ, phương thức sau tuyên bố rằng nó ném một Remote Exception và một Insufficient Funds Exception

Thí dụ

import java.io.*;
public class className {

   public void withdraw(double amount) throws RemoteException, 
      InsufficientFundsException {
      // Method implementation
   }
   // Remainder of class definition
}

Khối cuối cùng


Khối cuối cùng sau khối thử hoặc khối catch. Một khối mã cuối cùng luôn luôn thực hiện, bất kể sự xuất hiện của một ngoại lệ.

Việc sử dụng khối cuối cùng cho phép bạn chạy bất kỳ câu lệnh kiểu dọn dẹp nào mà bạn muốn thực thi, bất kể điều gì xảy ra trong mã được bảo vệ.

Một khối cuối cùng xuất hiện ở cuối khối catch và có cú pháp sau:

Cú pháp

try {
   // Protected code
} catch (ExceptionType1 e1) {
   // Catch block
} catch (ExceptionType2 e2) {
   // Catch block
} catch (ExceptionType3 e3) {
   // Catch block
}finally {
   // The finally block always executes.
}

Thí dụ

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");
      }
   }
}
Điều này sẽ tạo ra kết quả sau 

Đầu ra

Exception thrown  :java.lang.ArrayIndexOutOfBoundsException: 3
First element value: 6
The finally statement is executed

Lưu ý những điều sau đây 

Một mệnh đề catch không thể tồn tại mà không có câu lệnh try.

Nó không bắt buộc phải có mệnh đề cuối cùng bất cứ khi nào một khối try / catch có mặt.

Khối thử không thể có mặt mà không có mệnh đề bắt hoặc mệnh đề cuối cùng.

Bất kỳ mã nào không thể có mặt ở giữa try, catch, finally blocks.

Tài nguyên cố gắng

Nói chung, khi chúng tôi sử dụng bất kỳ tài nguyên nào như luồng, kết nối, v.v ... chúng tôi phải đóng chúng một cách rõ ràng bằng cách sử dụng khối cuối cùng. Trong chương trình sau, chúng ta đang đọc dữ liệu từ một tệp bằng FileReader và chúng ta sẽ đóng nó bằng cách sử dụng khối cuối cùng.

Thí dụ
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 , cũng được gọi là quản lý tài nguyên tự động , là một cơ chế xử lý ngoại lệ mới được giới thiệu trong Java 7, tự động đóng các tài nguyên được sử dụng trong khối try catch.

Để sử dụng câu lệnh này, bạn chỉ cần khai báo các tài nguyên được yêu cầu trong dấu ngoặc đơn và tài nguyên được tạo sẽ tự động được đóng ở cuối khối. Sau đây là cú pháp của câu lệnh try-with-resources.

Cú pháp

try(FileReader fr = new FileReader("file path")) {
   // use the resource
   } catch () {
      // body of catch 
   }
}

Sau đây là chương trình đọc dữ liệu trong một tệp bằng câu lệnh try-with-resources.

Thí dụ

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();
      }
   }
}

Các điểm sau đây cần lưu ý khi làm việc với câu lệnh try-with-resources.

Để sử dụng một lớp với câu lệnh try-with-resources, nó sẽ triển khai thực hiện giao diện AutoCloseable và phương thức close () của nó được gọi tự động khi chạy.

Bạn có thể khai báo nhiều hơn một lớp trong câu lệnh try-with-resources.

Trong khi bạn khai báo nhiều lớp trong khối try của câu lệnh try-with-resources, các lớp này được đóng theo thứ tự ngược lại.

Ngoại trừ việc khai báo tài nguyên trong ngoặc đơn cũng giống như khối try / catch bình thường của khối thử.

Tài nguyên được khai báo trong thử được khởi tạo ngay trước khi bắt đầu khối thử.

Tài nguyên được khai báo tại khối thử được ngầm khai báo là cuối cùng.

Ngoại lệ do người dùng xác định

Bạn có thể tạo các ngoại lệ của riêng bạn trong Java. Hãy lưu ý những điểm sau khi viết các lớp ngoại lệ của riêng bạn

Tất cả các ngoại lệ phải là một đứa trẻ của Throwable.

Nếu bạn muốn viết một ngoại lệ đã kiểm tra được quy tắc Xử lý hoặc Khai báo tự động thực thi, bạn cần phải mở rộng lớp Ngoại lệ.

Nếu bạn muốn viết một ngoại lệ thời gian chạy, bạn cần phải mở rộng lớp Runtime Exception.

Chúng ta có thể định nghĩa lớp Ngoại lệ của chúng ta như sau:

class MyException extends Exception {
}

Bạn chỉ cần mở rộng lớp Exception được xác định trước để tạo ra ngoại lệ của riêng bạn. Đây được coi là ngoại lệ được kiểm tra.

Lớp Insufficient Funds Exception sau đây là một ngoại lệ do người dùng định nghĩa mở rộng lớp Exception, làm cho nó trở thành một ngoại lệ được kiểm tra. Một lớp ngoại lệ giống như bất kỳ lớp nào khác, có chứa các trường và phương thức hữu ích.

Thí dụ

// 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;
   }
}
Để chứng minh bằng cách sử dụng ngoại lệ do người dùng định nghĩa của chúng tôi, lớp Checking Account sau đây chứa một phương thức cancel () để ném ra một Insufficient Funds Exception.
// 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;
   }
}
Chương trình BankDemo sau đây trình bày cách gọi phương thức deposit () và rút tiền () của 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();
      }
   }
}

Biên dịch tất cả ba tập tin trên và chạy BankDemo. Điều này sẽ tạo ra kết quả sau -

Đầu ra

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)

Ngoại lệ chung

Trong Java, có thể định nghĩa hai phần tử ngoại lệ và lỗi.

Ngoại lệ JVM - Đây là những ngoại lệ / lỗi được JVM độc quyền hoặc ném một cách hợp lý. Ví dụ: NullPointerException, ArrayIndexOutOfBoundsException, ClassCastException.

Ngoại lệ có lập trình - Các trường hợp ngoại lệ này được trình bày rõ ràng bởi ứng dụng hoặc lập trình viên API. Ví dụ: IllegalArgumentException, IllegalStateException.

Không có nhận xét nào:

Đăng nhận xét

Lập trình Java - Ngoại lệ

Một ngoại lệ (hoặc sự kiện đặc biệt) là một vấn đề phát sinh trong quá trình thực hiện chương trình. Khi xảy ra Ngoại lệ , luồng bình thường...