天天看點

Java入門 - 語言基礎 - 22.異常處理異常處理

原文位址: http://www.work100.net/training/java-exception.html 更多教程: 光束雲 - 免費課程

異常處理

請參照如上

章節導航

進行閱讀

1.概述

異常是程式中的一些錯誤,但并不是所有的錯誤都是異常,并且錯誤有時候是可以避免的。

比如說,你的代碼少了一個分号,那麼運作出來結果是提示是錯誤

java.lang.Error;

如果你用

System.out.println(11/0)

,那麼你是因為你用

做了除數,會抛出

java.lang.ArithmeticException

的異常。

異常發生的原因有很多,通常包含以下幾大類:

  • 使用者輸入了非法資料
  • 要打開的檔案不存在
  • 網絡通信時連接配接中斷,或者JVM記憶體溢出

這些異常有的是因為使用者錯誤引起,有的是程式錯誤引起的,還有其它一些是因為實體錯誤引起的。

要了解 Java 異常處理是如何工作的,你需要掌握以下三種類型的異常:

  • 檢查性異常:最具代表的檢查性異常是使用者錯誤或問題引起的異常,這是程式員無法預見的。例如要打開一個不存在檔案時,一個異常就發生了,這些異常在編譯時不能被簡單地忽略
  • 運作時異常: 運作時異常是可能被程式員避免的異常。與檢查性異常相反,運作時異常可以在編譯時被忽略
  • 錯誤: 錯誤不是異常,而是脫離程式員控制的問題。錯誤在代碼中通常被忽略。例如,當棧溢出時,一個錯誤就發生了,它們在編譯也檢查不到的

2.Exception類的層次

所有的異常類是從

java.lang.Exception

類繼承的子類。

Exception

類是

Throwable

類的子類。除了

Exception

類外,

Throwable

還有一個子類

Error

Java 程式通常不捕獲錯誤。錯誤一般發生在嚴重故障時,它們在 Java 程式處理的範疇之外。

Error

用來訓示運作時環境發生的錯誤。

例如,JVM 記憶體溢出。一般地,程式不會從錯誤中恢複。

異常類有兩個主要的子類:

IOException

類和

RuntimeException

類。

Java入門 - 語言基礎 - 22.異常處理異常處理

在 Java 内置類中(接下來會說明),有大部分常用檢查性和非檢查性異常。

3.内置異常類

Java 語言定義了一些異常類在

java.lang

标準包中。

标準運作時異常類的子類是最常見的異常類。由于

java.lang

包是預設加載到所有的 Java 程式的,是以大部分從運作時異常類繼承而來的異常都可以直接使用。

Java 根據各個類庫也定義了一些其他的異常,下面的表中列出了 Java 的非檢查性異常。

異常 描述

ArithmeticException

當出現異常的運算條件時,抛出此異常。例如,一個整數"除以零"時,抛出此類的一個執行個體

ArrayIndexOutOfBoundsException

用非法索引通路數組時抛出的異常。如果索引為負或大于等于數組大小,則該索引為非法索引

ArrayStoreException

試圖将錯誤類型的對象存儲到一個對象數組時抛出的異常

ClassCastException

當試圖将對象強制轉換為不是執行個體的子類時,抛出該異常

IllegalArgumentException

抛出的異常表明向方法傳遞了一個不合法或不正确的參數

IllegalMonitorStateException

抛出的異常表明某一線程已經試圖等待對象的螢幕,或者試圖通知其他正在等待對象的螢幕而本身沒有指定螢幕的線程

IllegalStateException

在非法或不适當的時間調用方法時産生的信号。換句話說,即 Java 環境或 Java 應用程式沒有處于請求操作所要求的适當狀态下

IllegalThreadStateException

線程沒有處于請求操作所要求的适當狀态時抛出的異常

IndexOutOfBoundsException

訓示某排序索引(例如對數組、字元串或向量的排序)超出範圍時抛出

NegativeArraySizeException

如果應用程式試圖建立大小為負的數組,則抛出該異常

NullPointerException

當應用程式試圖在需要對象的地方使用

null

時,抛出該異常

NumberFormatException

當應用程式試圖将字元串轉換成一種數值類型,但該字元串不能轉換為适當格式時,抛出該異常

SecurityException

由安全管理器抛出的異常,訓示存在安全侵犯

StringIndexOutOfBoundsException

此異常由

String

方法抛出,訓示索引或者為負,或者超出字元串的大小

UnsupportedOperationException

當不支援請求的操作時,抛出該異常

下面的表中列出了 Java 定義在

java.lang

包中的檢查性異常類。

ClassNotFoundException

應用程式試圖加載類時,找不到相應的類,抛出該異常。

CloneNotSupportedException

當調用

Object

類中的

clone

方法克隆對象,但該對象的類無法實作

Cloneable

接口時,抛出該異常。

IllegalAccessException

拒絕通路一個類的時候,抛出該異常。

InstantiationException

當試圖使用

Class

newInstance

方法建立一個類的執行個體,而指定的類對象因為是一個接口或是一個抽象類而無法執行個體化時,抛出該異常。

InterruptedException

一個線程被另一個線程中斷,抛出該異常。

NoSuchFieldException

請求的變量不存在

NoSuchMethodException

請求的方法不存在

4.異常方法

下面的清單是

Throwable

類的主要方法:

方法及說明

public String getMessage()

傳回關于發生的異常的詳細資訊。這個消息在

Throwable

類的構造函數中初始化了。

public Throwable getCause()

傳回一個

Throwable

對象代表異常原因。

public String toString()

使用

getMessage()

的結果傳回類的串級名字。

public void printStackTrace()

列印

toString()

結果和棧層次到

System.err

,即錯誤輸出流。

public StackTraceElement[] getStackTrace()

傳回一個包含堆棧層次的數組。下标為 的元素代表棧頂,最後一個元素代表方法調用堆棧的棧底。

public Throwable fillInStackTrace()

用目前的調用棧層次填充

Throwable

對象棧層次,添加到棧層次任何先前資訊中。

5.捕獲異常

try

catch

關鍵字可以捕獲異常。

try/catch

代碼塊放在異常可能發生的地方。

try/catch

代碼塊中的代碼稱為保護代碼,使用

try/catch

的文法如下:

try
{
   // 程式代碼
}catch(ExceptionName e1)
{
   //Catch 塊
}           

Catch

語句包含要捕獲異常類型的聲明。當保護代碼塊中發生一個異常時,

try

後面的

catch

塊就會被檢查。

如果發生的異常包含在

catch

塊中,異常會被傳遞到該

catch

塊,這和傳遞一個參數到方法是一樣。

執行個體

下面的例子中聲明有兩個元素的一個數組,當代碼試圖通路數組的第三個元素的時候就會抛出一個異常。

// 檔案名 : 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           

6.多重捕獲塊

一個

try

代碼塊後面跟随多個

catch

代碼塊的情況就叫多重捕獲。

多重捕獲塊的文法如下所示:

try{
   // 程式代碼
}catch(異常類型1 異常的變量名1){
  // 程式代碼
}catch(異常類型2 異常的變量名2){
  // 程式代碼
}catch(異常類型2 異常的變量名2){
  // 程式代碼
}           

上面的代碼段包含了 3 個

catch

塊。

可以在

try

語句後面添加任意數量的

catch

如果保護代碼中發生異常,異常被抛給第一個

catch

如果抛出異常的資料類型與

ExceptionType1

比對,它在這裡就會被捕獲。

如果不比對,它會被傳遞給第二個

catch

如此,直到異常被捕獲或者通過所有的

catch

該執行個體展示了怎麼使用多重

try/catch

try {
    file = new FileInputStream(fileName);
    x = (byte) file.read();
} catch(FileNotFoundException f) { // Not valid!
    f.printStackTrace();
    return -1;
} catch(IOException i) {
    i.printStackTrace();
    return -1;
}           

7.throws/throw關鍵字

如果一個方法沒有捕獲到一個檢查性異常,那麼該方法必須使用

throws

關鍵字來聲明。

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
}           

8.finally關鍵字

finally

關鍵字用來建立在

try

代碼塊後面執行的代碼塊。

無論是否發生異常,

finally

代碼塊中的代碼總會被執行。

finally

代碼塊中,可以運作清理類型等收尾善後性質的語句。

finally

代碼塊出現在

catch

代碼塊最後,文法如下:

try{
  // 程式代碼
}catch(異常類型1 異常的變量名1){
  // 程式代碼
}catch(異常類型2 異常的變量名2){
  // 程式代碼
}finally{
  // 程式代碼
}           

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

    後面添加

    finally

    塊并非強制性要求的
  • try

    代碼後不能既沒

    catch

    塊也沒

    finally

  • try

    ,

    catch

    finally

    塊之間不能添加任何代碼

9.聲明自定義異常

在 Java 中你可以自定義異常。編寫自己的異常類時需要記住下面的幾點:

  • 所有異常都必須是

    Throwable

    的子類
  • 如果希望寫一個檢查性異常類,則需要繼承

    Exception

  • 如果你想寫一個運作時異常類,那麼需要繼承

    RuntimeException

可以像下面這樣定義自己的異常類:

class MyException extends Exception{
}           

隻繼承

Exception

類來建立的異常類是檢查性異常類。

下面的

InsufficientFundsException

類是使用者定義的異常類,它繼承自

Exception

一個異常類和其它任何類一樣,包含有變量和方法。

以下執行個體是一個銀行賬戶的模拟,通過銀行卡的号碼完成識别,可以進行存錢和取錢的操作。

// 檔案名InsufficientFundsException.java
import java.io.*;
 
//自定義異常類,繼承Exception類
public class InsufficientFundsException extends Exception
{
  //此處的amount用來儲存當出現異常(取出錢多于餘額時)所缺乏的錢
  private double amount;
  public InsufficientFundsException(double amount)
  {
    this.amount = amount;
  } 
  public double getAmount()
  {
    return amount;
  }
}           

為了展示如何使用我們自定義的異常類,

在下面的

CheckingAccount

類中包含一個

withdraw()

方法抛出一個

InsufficientFundsException

異常。

// 檔案名稱 CheckingAccount.java
import java.io.*;
 
//此類模拟銀行賬戶
public class CheckingAccount
{
  //balance為餘額,number為卡号
   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

類的

deposit()

withdraw()

方法。

//檔案名稱 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)           

10.通用異常

在Java中定義了兩種類型的異常和錯誤。

  • JVM(Java虛拟機)異常:由 JVM 抛出的異常或錯誤。例如:

    NullPointerException

    類,

    ArrayIndexOutOfBoundsException

    ClassCastException

  • 程式級異常:由程式或者API程式抛出的異常。例如

    IllegalArgumentException

    IllegalStateException

上一篇:

Scanner類
如果對課程内容感興趣,可以掃碼關注我們的

公衆号

QQ群

,及時關注我們的課程更新
Java入門 - 語言基礎 - 22.異常處理異常處理
Java入門 - 語言基礎 - 22.異常處理異常處理