Java 異常處理

Java 異常處理

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

比如說穆役,代碼少了一個分號寸五,那么運行出來結果是提示是錯誤 java.lang.Error

再比如,如果用 System.out.println(11/0)耿币,因為用 0 做了除數梳杏,會拋出 java.lang.ArithmeticException 的異常

異常發(fā)生的原因有很多,通常包含以下幾大類

  1. 用戶輸入了非法數據
  2. 要打開的文件不存在
  3. 網絡通信時連接中斷淹接,或者 JVM 內存溢出

這些異常有的是因為用戶錯誤引起十性,有的是程序錯誤引起的,還有其它一些是因為物理錯誤引起的

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

  1. 檢查性異常: 最具代表的檢查性異常是用戶錯誤或問題引起的異常劲适,這是程序員無法預見的。例如要打開一個不存在文件時厢蒜,一個異常就發(fā)生了霞势,這些異常在編譯時不能被簡單地忽略
  2. 運行時異常: 運行時異常是可能被程序員避免的異常。與檢查性異常相反斑鸦,運行時異炽倒保可以在編譯時被忽略
  3. 錯誤: 錯誤不是異常,而是脫離程序員控制的問題巷屿。錯誤在代碼中通常被忽略固以。例如,當棧溢出時嘱巾,一個錯誤就發(fā)生了憨琳,它們在編譯也檢查不到的

Exception 類的層次

所有的異常類是從 java.lang.Exception 類繼承的子類

Exception 類是 Throwable 類的子類

除了 Exception 類外,Throwable 還有一個子類 Error

Error 用來指示運行時環(huán)境發(fā)生的錯誤

Java 程序通常不捕獲錯誤浓冒,錯誤一般發(fā)生在嚴重故障時栽渴,它們在 Java 程序處理的范疇之外

例如,JVM 內存溢出稳懒。一般地闲擦,程序不會從錯誤中恢復

異常類有兩個主要的子類:IOException 類和 RuntimeException 類

image

Java 內置異常類

Java 在 java.lang 包中定義了一些異常類

標準運行時異常類的子類是最常見的異常類

由于 java.lang 包是默認加載到所有的 Java 程序的,所以大部分從運行時異常類繼承而來的異常都可以直接使用

Java 根據各個類庫也定義了一些其他的異常

下表中列出了 Java 的非檢查性異常

異常 描述
ArithmeticException 當出現異常的運算條件時场梆,拋出此異常墅冷。例如,一個整數"除以零"時或油,拋出此類的一個實例
ArrayIndexOutOfBoundsException 用非法索引訪問數組時拋出的異常寞忿。如果索引為負或大于等于數組大小,則該索引為非法索引
ArrayStoreException 試圖將錯誤類型的對象存儲到一個對象數組時拋出的異常
ClassCastException 當試圖將對象強制轉換為不是實例的子類時顶岸,拋出該異常
IllegalArgumentException 拋出的異常表明向方法傳遞了一個不合法或不正確的參數
IllegalMonitorStateException 拋出的異常表明某一線程已經試圖等待對象的監(jiān)視器腔彰,或者試圖通知其他正在等待對象的監(jiān)視器而本身沒有指定監(jiān)視器的線程
IllegalStateException 在非法或不適當的時間調用方法時產生的信號叫编。換句話說,即 Java 環(huán)境或 Java 應用程序沒有處于請求操作所要求的適當狀態(tài)下
IllegalThreadStateException 線程沒有處于請求操作所要求的適當狀態(tài)時拋出的異常
IndexOutOfBoundsException 指示某排序索引(例如對數組霹抛、字符串或向量的排序)超出范圍時拋出
NegativeArraySizeException 如果應用程序試圖創(chuàng)建大小為負的數組搓逾,則拋出該異常
NullPointerException 當應用程序試圖在需要對象的地方使用null時,拋出該異常
NumberFormatException 當應用程序試圖將字符串轉換成一種數值類型杯拐,但該字符串不能轉換為適當格式時霞篡,拋出該異常
SecurityException 由安全管理器拋出的異常,指示存在安全侵犯
StringIndexOutOfBoundsException 此異常由String方法拋出端逼,指示索引或者為負朗兵,或者超出字符串的大小
UnsupportedOperationException 當不支持請求的操作時,拋出該異常

下表中列出了定義在 java.lang 包中的檢查性異常類

異常 描述
ClassNotFoundException 應用程序試圖加載類時顶滩,找不到相應的類余掖,拋出該異常
CloneNotSupportedException 當調用Object類中的clone方法克隆對象,但該對象的類無法實現Cloneable接口時诲祸,拋出該異常
IllegalAccessException 拒絕訪問一個類的時候浊吏,拋出該異常
InstantiationException 當試圖使用Class類中的newInstance方法創(chuàng)建一個類的實例,而指定的類對象因為是一個接口或是一個抽象類而無法實例化時救氯,拋出該異常
InterruptedException 一個線程被另一個線程中斷找田,拋出該異常
NoSuchFieldException 請求的變量不存在
NoSuchMethodException 請求的方法不存在

Throwable 類提供的方法

下表列出了 Throwable 類的主要方法

方法及說明
public String getMessage()
返回關于發(fā)生的異常的詳細信息。這個消息在Throwable 類的構造函數中初始化了
public Throwable getCause()
返回一個 Throwable 對象代表異常原因
public String toString()
使用getMessage()的結果返回類的串級名字
public void printStackTrace()
打印toString()結果和棧層次到System.err着憨,即錯誤輸出流
public StackTraceElement [] getStackTrace()
返回一個包含堆棧層次的數組墩衙。下標為0的元素代表棧頂,最后一個元素代表方法調用堆棧的棧底
public Throwable fillInStackTrace()
用當前的調用棧層次填充 Throwable 對象棧層次甲抖,添加到棧層次任何先前信息中

捕獲異常

可以使用 try 和 catch 關鍵字可以捕獲異常

try/catch 語句塊可以放在異称岣模可能發(fā)生的地方

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

try 語句塊中的的代碼稱為保護代碼

catch 語句包含要捕獲異常類型的聲明,當保護代碼塊中發(fā)生一個異常時准谚,try 后面的 catch 塊就會被檢查

如果發(fā)生的異常包含在 catch 塊中挫剑,異常會被傳遞到該 catch 塊,這和傳遞一個參數到方法是一樣

范例

下面的范例聲明有兩個元素的一個數組柱衔,當代碼試圖訪問數組的第三個元素的時候就會拋出一個異常

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

編譯運行以上 Java 語句樊破,輸出結果如下

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

多重捕獲塊

try 語句后面可以添加任意數量的 catch 語句塊

一個 try 語句塊后面可以跟多個 catch 代碼塊的情況就叫多重捕獲

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

上面的代碼段包含了 3 個 catch 塊

這些 catch 語句塊的運行邏輯如下

  1. 如果保護代碼中發(fā)生異常,異常被拋給第一個 catch 塊

  2. 如果拋出異常的數據類型與 ExceptionType1 匹配唆铐,它在這里就會被捕獲

  3. 如果不匹配哲戚,它會被傳遞給第二個 catch 塊

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

下面的代碼演示了如何使用多重 try/catch

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

throws / throw 關鍵字

如果一個方法沒有捕獲一個檢查性異常艾岂,那么該方法必須使用 throws 關鍵字來聲明

throws 關鍵字放在方法簽名的尾部

throw 關鍵字則用于拋出一個異常顺少,無論它是新實例化的還是剛捕獲到的

下面方法的聲明拋出一個 RemoteException 異常

import java.io.*;
public class className
{
    public void deposit(double amount) throws RemoteException
    {

        // 方法實現
        throw new RemoteException();
    }

    // 其它類的屬性和方法定義
}

一個方法可以聲明拋出多個異常,多個異常之間用逗號隔開

下面的方法聲明拋出 RemoteException 和 InsufficientFundsException

import java.io.*;
public class className
{
    public void withdraw(double amount) throws RemoteException,
                              InsufficientFundsException
    {
        // 方法語句塊
    }

   // ... 類的其它方法定義
}

finally 語句

finally 語句用來創(chuàng)建在 try 代碼塊后面執(zhí)行的代碼塊

無論是否發(fā)生異常,finally 代碼塊中的代碼總會被執(zhí)行

因此可以在 finally 代碼塊中運行清理類型等收尾善后性質的語句

finally 代碼塊出現在 catch 代碼塊最后

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

下面的范例演示了如何使用 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");
        }
    }
}

編譯運行以上 Java 代碼脆炎,輸出結果如下

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

try...catch...finally 注意點

try...catch...finally 語句在使用過程中梅猿,有幾點需要注意

  1. catch 不能獨立于 try 存在
  2. 在 try/catch 后面添加 finally 塊并非強制性要求的
  3. try 代碼后不能既沒 catch 塊也沒 finally 塊
  4. try, catch, finally 塊之間不能添加任何代碼

自定義異常

Java 允許開發(fā)者自定義異常

class MyException extends Exception{}

但有幾點規(guī)則需要遵守

  1. 所有異常都必須是 Throwable 的子類
  2. 如果希望寫一個檢查性異常類,則需要繼承 Exception 類
  3. 如果你想寫一個運行時異常類腕窥,那么需要繼承 RuntimeException 類

只繼承 Exception 類來創(chuàng)建的異常類是檢查性異常類

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

下面的 InsufficientFundsException 類是用戶定義的異常類簇爆,它繼承自 Exception

范例

下面的范例是一個銀行賬戶的模擬,通過銀行卡的號碼完成識別爽撒,可以進行存錢和取錢的操作

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 異常

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

然后我們就可以寫一個測試類調用 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();
        }
    }
}

編譯運行上面的 3 個文件哨毁,輸出結果如下

Depositing 500... Withdrawing100...
Withdrawing 600... Sorry, but you are short200.0
InsufficientFundsException
at CheckingAccount.withdraw(CheckingAccount.java:25)
at BankDemo.main(BankDemo.java:13)

異常級別

Java 程序中有兩種級別的異常和錯誤

  1. JVM( Java 虛擬機 ) 異常: 由 JVM 拋出的異常或錯誤

    例如:NullPointerException 類源武,ArrayIndexOutOfBoundsException 類扼褪,ClassCastException 類

  2. 程序級異常: 由程序或者 API 程序拋出的異常

    例如 IllegalArgumentException 類,IllegalStateException 類

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末粱栖,一起剝皮案震驚了整個濱河市话浇,隨后出現的幾起案子,更是在濱河造成了極大的恐慌闹究,老刑警劉巖幔崖,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異渣淤,居然都是意外死亡赏寇,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進店門价认,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嗅定,“玉大人,你說我怎么就攤上這事用踩∏耍” “怎么了?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵捶箱,是天一觀的道長智什。 經常有香客問我,道長丁屎,這世上最難降的妖魔是什么荠锭? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮晨川,結果婚禮上证九,老公的妹妹穿的比我還像新娘删豺。我一直安慰自己,他們只是感情好愧怜,可當我...
    茶點故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布呀页。 她就那樣靜靜地躺著,像睡著了一般拥坛。 火紅的嫁衣襯著肌膚如雪蓬蝶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天猜惋,我揣著相機與錄音丸氛,去河邊找鬼。 笑死著摔,一個胖子當著我的面吹牛缓窜,可吹牛的內容都是我干的。 我是一名探鬼主播谍咆,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼禾锤,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了摹察?” 一聲冷哼從身側響起恩掷,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎港粱,沒想到半個月后螃成,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡查坪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年寸宏,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片偿曙。...
    茶點故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡氮凝,死狀恐怖,靈堂內的尸體忽然破棺而出望忆,到底是詐尸還是另有隱情罩阵,我是刑警寧澤,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布启摄,位于F島的核電站稿壁,受9級特大地震影響,放射性物質發(fā)生泄漏歉备。R本人自食惡果不足惜傅是,卻給世界環(huán)境...
    茶點故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧喧笔,春花似錦帽驯、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至浆劲,卻和暖如春嫌术,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背梳侨。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工蛉威, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人走哺。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像哲虾,于是被迫代替她去往敵國和親丙躏。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,455評論 2 359

推薦閱讀更多精彩內容

  • 來源:https://www.cnblogs.com/Qian123/p/5715402.html#_label0...
    Alex筆記閱讀 377評論 0 1
  • 異常分類 Java將異常分為兩種殃恒,Checked異常和Runtime異常榛丢。Java認為Checked異常都是可以在...
    LLorenzo閱讀 720評論 0 1
  • 2.JAVA異常 異常指不期而至的各種狀況筒狠,如:文件找不到、網絡連接失敗废恋、非法參數等。異常是一個事件扒寄,它發(fā)生在程...
    青城樓主閱讀 561評論 0 0
  • Java異常類型 所有異常類型都是Throwable的子類鱼鼓,Throwable把異常分成兩個不同分支的子類Erro...
    予別她閱讀 932評論 0 2
  • 【一】 “第二個……” 男人拭去刀刃上血漬,恢復了凌冽冰寒该编。他瞥了一眼一旁暈厥的女子和襁褓里瞪著大眼睛目不轉睛盯著...
    方壺閱讀 453評論 3 7