異常處理

拋出異常

異常處理使得程序可以處理非預期的情景,并且能夠繼續正常的操作

在java中,運行時錯誤會作為異常拋出。異常就是一種對象,表示阻止正常進行程序執行的錯誤或者情況。

異常是從方法拋出的。方法的調用者可以捕獲以及處理該異常。
我們可以先從簡單的算術異常錯誤來了解拋出異常的作用

import java.util.Scanner;
public class Quotient {
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        System.out.println("Enter two integers: ");
        int number1=input.nextInt();
        int number2=input.nextInt();
        System.out.println(number1+" / "+number2+" is "+(number1/number2));
    }
}
第二個整數為0時,產生錯誤

當第二個數字輸入的是數字0的時候,就會產生一個運行時錯誤,因為不能用一個整數除以一個0(但是在java中浮點型除以0將不會拋出異常)
要想解決這個錯誤,一個簡單的方法就是添加一個if語句來測試第二個數字。

import java.util.Scanner;
public class Quotient {
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        System.out.println("Enter two integers: ");
        int number1=input.nextInt();
        int number2=input.nextInt();
        if(number2!=0)
        System.out.println(number1+" / "+number2+" is "+(number1/number2));
        else
            System.out.println("Divisor cannot be zero");
    }
}
第二個整數為0時,沒有錯誤了

為了介紹異常處理,重新再寫一個方法來計算商。

import java.util.Scanner;
public class QuotienWithMethod {
    public static int quotient(int number1,int number2){
        if(number2==0){
            System.out.println("Divisor cannot be zero");
            System.exit(1);//表示程序非正常退出
        }
        return number1/number2;
    }
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        int number1=input.nextInt();
        int number2=input.nextInt();
        
        int result=quotient(number1, number2);
        System.out.println(number1+" / "+number2+" is "+result);
    }
}
沒有彈出錯誤

但是這種方法是強行結束掉整個程序,而且不應該是被調用的方法來結束整個程序,而是應該由調用者來決定是否終止程序。所以要用到異常處理。

import java.util.Scanner;
public class QuotientWithException {
    public static int quotient(int number1,int number2){
        if(number2==0)
            throw new ArithmeticException("Divisor cannot be zero");
        return number1/number2;
    }
    public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        System.out.println("Enter two integers: ");
        int number1=input.nextInt();
        int number2=input.nextInt();
        try{
            int result=quotient(number1,number2);
            System.out.println(number1+" / "+number2+" is "+result);
        }
        catch(ArithmeticException ex){
            System.out.println("Exception: an integer"+"cannot be divided by zero");
        }
        System.out.println("Execution continues...");
    }
}
拋出異常之后程序未終止

如果number2為0,方法就會通過執行下面的語句來拋出異常

throw new ArithmeticException("Divisor cannot be zero");

在這種情況下,拋出的值為new ArithmeticException("Divisor cannot be zero"),就成為一個異常(exception)。throw語句的執行稱為拋出一個異常(throwing an exception)。異常就是一個從異常類創建的對象。在這種情況下,異常類就是java.lang.ArithmeticException.構造方法ArithmeticException(str)被調用來構建一個異常,其中str就是用來描述異常的信息。
當異常被拋出的時候后,正常的執行流程會被中斷。異常會從一個地方傳遞到另一個地方。調用方法的語句包含在一個try塊和一個catch塊中。try塊包含了正常情況之下執行的代碼。異常會被catch塊捕獲。catch塊中的語句用來處理異常,然后執行catch塊之后的語句(相當于是throw語句調用了catch塊,但是catch塊執行完畢之后不會返回到throw語句之后,而是直接運行catch塊之后的語句)。

catch塊的頭部:

catch (ArithmeticException ex)

標識符ex的作用很像是方法中的參數。所以,這個參數稱為catch塊的參數。ex之前的類型(例如,ArithmeticException)指定了catch塊可以捕獲的異常類型。一旦捕獲該異常,就能從catch塊體中的參數方訪問這個拋出的值。
總之,一個try-throw-catch塊的模板可能會如下所示:

try{
    Code to run;
    A statement or a method that may throw an exception;
    More code to run;
}
catch(type ex){
    Code to process the exception;
} 

一個異常可能是通過try塊中的throw語句直接拋出,或者調用一個可能會拋出異常的方法二拋出。
什么是拋出異常的優點?

異常處理可以使方法拋出一個異常給它的調用者,并由調用者處理該異常。如果沒有這個能力,那么被調用的方法就必須自己處理異常或者終止改程序。被調用的方法通常不知道在出錯的情況下該做一些什么,這是庫方法的一般情況。庫方法可以檢測出錯誤,但是只有調用者才知道出現錯誤的時候需要做什么。異常處理最根本的優勢就是將檢測錯誤(由被調用的方法完成)從處理錯誤(由調用方法完成)中分離出來。

異常是對象,而對象都采用類來定義。異常的根類是java.lang.Throwable。

Throwable類是所有異常類的根。所有的java異常類都直接或者間接地繼承自Throwable類。我們可以通過繼承Exception或者Exception的子類來創建自己的異常類。
異常類可以分為三種類型:系統錯誤、 異常、 運行時異常

  • 系統錯誤(system error):是由java虛擬機拋出的,用error類表示。Error類描述的是系統內部錯誤。
  • 異常(Exception):是用Exception類表示的,他描述的是由程序和外部環境所引起的錯誤,這些錯誤可以能被程序捕獲和處理。
  • 運行時錯誤(runtime exception)是用RuntimeException類表示的,它描述的是程序設計錯誤。
    RuntimeException、Error以及它們的子類都稱為免檢異常(unchecked exception),而其他所有異常都稱為必檢異常(checked exception)因為免檢異常可能出現在程序的任意一個地方,為了避免過多地使用try-catch塊,所以免檢異常不作強制要求。

Java的異常處理模基于三種操作:聲明一個異常、拋出一個異常、捕獲一個異常。

聲明異常:在Java中,當前執行的語句必屬于某個方法。Java解釋器調用main方法開始執行一個程序。每個方法都必須聲明它可能拋出的必檢異常類型。

public void myMethod() throws IOException

拋出異常:檢測到錯誤的程序可以創建一個合適的異常類型的實例并拋出它,這就成為拋出一個異常。

IllegalArgumentException ex=new IllegalArgumentException("Wrong Argument");
throw ex;

或者用下面這種方法

throw new IllegalArgumentException("Wrong Argument");

每個異常類至少有兩個構造方法:一個無參構造方法和一個帶可描述這個異常的String參數的構造函數。這個String參數稱為異常消息,可以用getMessage();獲取。
聲明異常的關鍵字是throws,拋出異常的關鍵字是throw。
捕獲異常:當拋出一個異常時,可以在try-catch塊中捕獲和處理它。

try{
    statements;
}
catch (Exception ex){
    handler for exception;
}

如果在執行try塊中代碼的過程中沒有出現異常,則會跳過catch語句。如果try塊中的某條語句拋出一個異常,java會跳過try塊中剩下的語句。
從一個通用的父類可以派生出各種異常類。如果一個catch塊可以捕獲一個父類的異常對象,它就能捕獲那個父類的所有子類的異常對象。而且如果父類的catch塊出現在子類的catch塊漆面,會導致編譯錯誤。
Java要求程序員必須處理必檢異常。如果方法聲明了一個必檢異常,就必須在try-catch塊中調用它,或在調用方法中聲明要拋出異常。
要是需要一個catch塊捕獲多個異常可以使用"|"來將每個異常類型隔開。
從異常中獲取信息


public class TestException {
    public static void main(String[] args) {
        try{
            System.out.println(sum(new int[]{1,2,3,4,5}));
        }
            catch (Exception ex){
                ex.printStackTrace();
                System.out.println("\n"+ex.getMessage());
                System.out.println("\n"+ex.toString());
                
                System.out.println("\nTrace Info Obtained from getStackTrace");
                StackTraceElement[] traceElements=ex.getStackTrace();
                for(int i=0;i<traceElements.length;i++){
                    System.out.println("method"+traceElements[i].getMethodName());
                    System.out.println("("+traceElements[i].getClassName()+":");
                    System.out.println(traceElements[i].getLineNumber()+")");
                }
            }
        }
    private static int sum(int [] list){
        int result=0;
        for(int i=0;i<=list.length;i++)
            result+=list[i];
            return result;
    }
}

在代碼中使用了printStackTrace();、getMessage();、toString();三種方法來顯示棧跟蹤、異常信息、異常對象和信息。

運行結果:

printStackTrace();顯示棧跟蹤
getMessage();顯示異常信息
toString();顯示異常對象和信息
getStackTrace();顯示調用的方法

finally子句

有時候,不論異常是否會出現或者被捕獲,都希望執行某一些代碼,這個時候可以使用finally子句來達到這個目的。

try{
    statements;
}
catch(TheException ex){
    handling ex;
}
finally{
    finalStatements;
}

注意:使用finally子句時可以省略掉catch塊。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,885評論 6 541
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,312評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,993評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,667評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,410評論 6 411
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,778評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,775評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,955評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,521評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,266評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,468評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,998評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,696評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,095評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,385評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,193評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,431評論 2 378

推薦閱讀更多精彩內容

  • 六種異常處理的陋習 你覺得自己是一個Java專家嗎?是否肯定自己已經全面掌握了Java的異常處理機制?在下面這段代...
    Executing閱讀 1,352評論 0 6
  • 初識異常(Exception) 比如我們在取數組里面的某個值得時候,經常會出現定義的取值范圍超過了數組的大小,那么...
    iDaniel閱讀 1,878評論 1 2
  • Java異常類型 所有異常類型都是Throwable的子類,Throwable把異常分成兩個不同分支的子類Erro...
    予別她閱讀 942評論 0 2
  • __________觀音山有感 觀音山,一直沒看,單看名字,不太喜歡。 昨天不經意間點開了,畫面開始,范冰冰在化妝...
    米酒黑布林閱讀 406評論 1 0
  • 木本植物是什么呢? 這里元寶楓小編來解釋一下,哦,對了,元寶楓也是一種木本植物哦! 木本植物是是指根和莖因增粗生長...
    九尾貓貓閱讀 4,147評論 0 1