Java Basics Part 19/20 - Exceptions

Java Basics Part 19/20 - Exceptions

目錄


異常(Exception) 是運行期出現錯誤帶來的問題。當程序發生異常的時候,會不正常終止,而這不是程序員想看到,所以就引入了 異常機制,來處理運行期拋出的異常。

異常可以由很多因素導致,下面是一些常見的異常場景:

  • 用戶輸入非法數據
  • 需要打開的文件不存在
  • 在通信過程中網絡斷開或者是 JVM 內存溢出了

一些異常由用戶錯誤導致,還有一些有程序員導致,還有一些是物理資源導致。

基於上述原因種類不同,我們可以給異常分類:

  • Checked exceptions:checked exception 是在編譯期間出現的異常,這些異常也叫作編譯期異常。它們在編譯期不能忽略,程序員應該把這些異常處理掉。
    比如,如果使用 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); 
       }
    
    }
    
    // output
    FilenotFound_Demo.java:8: error: unreported exception     FileNotFoundException; must be caught or declared to be thrown
      FileReader fr = new FileReader(file);
  • Unchecked exceptions:Unchecked exceptions 是運行期會發生的異常,又叫做運行期異常,這些異常包括程序 bug,比如邏輯錯誤,API 的錯誤使用等等這些在編譯器會忽略的異常。

    public class Unchecked_Demo {   
        public static void main(String args[]){
            int num[]={1,2,3,4};
            System.out.println(num[5]);
         }
    }
    // output
    Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
    at Exceptions.Unchecked_Demo.main(Unchecked_Demo.java:8)
  • Errors: 這些不是異常,而是一些程序員無法控制的問題。比如,棧溢出。


Exception Hierarchy

所有的 Exception 都是 java.lang.Exception 的子類。Exception 同時也是 Throwable 的子類。除了 Exception 之外,還有 Error 類也是 Throwable 的子類。

Exception 類有兩個子類:IOException 和 RuntimeException。

Exception

這裏有常見的 java 內置 Exception.


Exceptions Methods

下面列出了 Throwable 類的一些很重要的方法。

SN Methods with Description
1 public String getMessage():異常發生時返回的錯誤信息,這個信息在異常類構造器中初始化的。
2 public Throwable getCause():返回異常的原因
3 public String toString():返回類名+getMessage()
4 public void printStackTrace():打印 toString() 的結果,輸出到 System.err
5 public StackTraceElement [] getStackTrace():返回調用棧元素的集合
6 public Throwable fillInStackTrace()

Catching Exceptions

可以使用 trycatch 來捕獲異常。語法如下:

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

舉例:

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

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

Multiple catch Blocks

一個 try,後面可以接多個 catch:

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

舉例:

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

Catching multiple type of exceptions

從 Java 7 開始,一個 catch 語句塊可以捕獲多個異常。比如:

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

The throws/throw Keywords

如果方法本身不會處理一個 checked exception,那麼方法必須使用 throws 拋出這個異常。throws 關鍵字總是出現在方法簽名的末尾。

方法中也可以使用 throw 關鍵字拋出一個異常。

throwsthrow 的區別:
throws 用來推遲 checked exception 的處理,throw 用來顯示的觸發一個異常。

下面這個例子,拋出了一個 RemoteException:

import java.io.*;
public class className
{
   public void deposit(double amount) throws RemoteException
   {
      // Method implementation
      throw new RemoteException();
   }
   //Remainder of class definition
}

方法也可以一次拋出多個異常。

import java.io.*;
public class className
{
   public void withdraw(double amount) throws RemoteException,
                              InsufficientFundsException
   {
       // Method implementation
   }
   //Remainder of class definition
}

The finally block

finally 塊緊跟在 try…catch 後面。finally 塊中的語句總是會執行,即使有異常發生。

通常使用 finally 語句塊來做一些資源清理的工作。

語法如下:

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

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

注意:

  • 無 try 不 catch
  • finally 不必在
  • 無 catch 或 finally 不 try
  • try catch finally 之間無代碼

The try-with-resources

通常我們會使用一些資源(流,連接等等),使用完成後要關掉這些資源,如下所示,使用 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 句法後(Java 7 引進),try 中打開的資源會自動釋放。
語法:

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

舉例:

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 打開的類,必須實現 AutoCloseable接口,運行期會自動調用close()
  • 在 try-with-resources 中可用聲明多個類
  • try 中聲明的多個類會以相反的順序關閉
  • 除了資源的聲明之外,其他與 try/catch 無異
  • try 中聲明的資源在 try 開始之前被初始化。
  • try 中聲明的資源隱式的被修飾爲 final 的

User-Define Exceptions

用戶可以創建自己的異常類。自定義的時候注意以下幾點:

  • 所有的異常都是 Throwable 的子類
  • 如果想寫一個 checked exception,需要繼承 Exception
  • 如果想寫一個 runtime exception,需要繼承 RuntimeException

舉例:

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

使用上述定義的異常:

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

使用上述定義的類:

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

// output
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)

Common Exceptions

Java 中,可以定義兩種 Exceptions 和 Errors:

  • JVM Exceptions: 由 JVM 拋出的異常,例如:NullPointerException,ArrayIndexOutOfBoundsException,ClassCastException
  • Programmatic exceptions: 應用或者是API設計者拋出的異常,例如:IllegalArgumentException,IllegalStateException
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章