異常處理

拋出異常

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

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

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

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));
    }
}
第二個整數(shù)為0時,產(chǎn)生錯誤

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

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");
    }
}
第二個整數(shù)為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);
    }
}
沒有彈出錯誤

但是這種方法是強(qiáng)行結(jié)束掉整個程序,而且不應(yīng)該是被調(diào)用的方法來結(jié)束整個程序,而是應(yīng)該由調(diào)用者來決定是否終止程序。所以要用到異常處理。

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,方法就會通過執(zhí)行下面的語句來拋出異常

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

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

catch塊的頭部:

catch (ArithmeticException ex)

標(biāo)識符ex的作用很像是方法中的參數(shù)。所以,這個參數(shù)稱為catch塊的參數(shù)。ex之前的類型(例如,ArithmeticException)指定了catch塊可以捕獲的異常類型。一旦捕獲該異常,就能從catch塊體中的參數(shù)方訪問這個拋出的值。
總之,一個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語句直接拋出,或者調(diào)用一個可能會拋出異常的方法二拋出。
什么是拋出異常的優(yōu)點?

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

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

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

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

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

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

public void myMethod() throws IOException

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

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

或者用下面這種方法

throw new IllegalArgumentException("Wrong Argument");

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

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

如果在執(zhí)行try塊中代碼的過程中沒有出現(xiàn)異常,則會跳過catch語句。如果try塊中的某條語句拋出一個異常,java會跳過try塊中剩下的語句。
從一個通用的父類可以派生出各種異常類。如果一個catch塊可以捕獲一個父類的異常對象,它就能捕獲那個父類的所有子類的異常對象。而且如果父類的catch塊出現(xiàn)在子類的catch塊漆面,會導(dǎo)致編譯錯誤。
Java要求程序員必須處理必檢異常。如果方法聲明了一個必檢異常,就必須在try-catch塊中調(diào)用它,或在調(diào)用方法中聲明要拋出異常。
要是需要一個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();三種方法來顯示棧跟蹤、異常信息、異常對象和信息。

運(yùn)行結(jié)果:

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

finally子句

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

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

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