欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一文給你通俗易懂的講解Java異常

 更新時間:2021年05月02日 10:30:46   作者:ithuangqing  
這篇文章主要給大家介紹了關于Java異常的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

什么是異常?

最簡單的,看一個代碼示例:

public static void main(String[] args) {
        int a = 1;
        int b = 0;
        System.out.println(a / b);
    }

這段代碼有什么問題?簡單,除數(shù)不能為0對吧,我們打印輸出:

顯而易見,程序出問題了,不能正常執(zhí)行了,這里出現(xiàn)了一些爆紅的信息,這些就是異常提示,這就是Java中提供的異常機制,當你的程序存在問題的情況下,會給你打印輸出一些信息,這個就叫做異常信息。

字面意思上去理解,所謂“異?!币簿褪恰安徽!?,放在代碼程序中就是那些導致不能正確執(zhí)行的問題,比如上述代碼,Java就會給你打印出為啥此段代碼不能正確執(zhí)行,給你輸出不正常的信息,這樣你就可以根據(jù)異常信息去修改代碼,從而提高代碼的健壯性!

詳細聊聊異常

以上我們簡單看了下一個具體的異常,下面我們就“何為異?!痹僦卑椎奶接懸幌?,異常作為一種代碼的處理機制,現(xiàn)在基本上大多數(shù)的編程語言都包含有這個異常機制,但是,我門熟知的偉大的C語言是沒有異常處理機制的。

大多數(shù)的高級語言,比如Java,python,C++這些都包含非常完善的異常處理機制,既然有這個玩意,那自然有它的好處,一般來說吧,擁有異常機制可以是我們的代碼:

  • 擁有更好的容錯性
  • 更加的健壯

那啥意思嘞?啥是容錯性,啥又是健壯呢?

首先是容錯性,這個通俗來講,就是可承受錯誤的范圍和概率,比如說我們的程序要是沒有異常機制的話,那很多錯誤是無法承受的,可能一旦出現(xiàn)錯誤,就會導致我們的系統(tǒng)崩潰出大問題,這個帶來的后果可能比較嚴重,但是具有異常機制,就可以幫助我們?nèi)ヌ幚硪恍╁e誤,以至于即使出現(xiàn)錯誤也不會造成這么嚴重的后果。

那什么又是健壯呢?這個一般就是說我們的代碼比較安全,不容易出現(xiàn)bug,基本上把該想到的情況都想到了,代碼編寫比較嚴謹,不容易出錯,質量好,這個一般就可以說我們的代碼比較健壯。

當然,以上只是我粗淺的理解,希望能夠幫助大家對異常機制的理解。

那再來說異常,其實就是不好的東西,比如我們的代碼有bug,程序出錯等等,這些都是有可能發(fā)生的,誰也不能保證自己寫的代碼一定是正確的,對吧。

異常也就是代碼中可能出現(xiàn)的意外情況,這就要求我們在編寫代碼的時候盡量考慮全面,但是即使你考慮的再全面也不可能將所有的意外情況都考慮進去,所以,實際當中意外情況會有發(fā)生的概率,對于這種我們無法考慮周到的意外情況,就需要我們的異常機制去處理了。

Java中的異常

接下來我們來看看Java中的異常,想必大家多多少少都會聽說過這樣一個異常叫做空指針異常,我們來看代碼演示:

NullPointerException nullPointerException = new NullPointerException("空指針異常");
        System.out.println(nullPointerException);

可以發(fā)現(xiàn),在Java真實存在NullPointerException這個類,而我們可以通過這個類去創(chuàng)建具體的異常對象,比如這里的空指針異常對象,我們打印輸出看看:

如此來看,在Java中,異常是以類的形式存在的,而且我們可以通過這些異常類去創(chuàng)建相應的異常對象,那么我們再來看這段代碼:

public static void main(String[] args) {
        int a = 1;
        int b = 0;
        System.out.println(a / b);
    }

這里會出現(xiàn)異常,其實實際上就是在運行到“ System.out.println(a / b);”的時候Jvm虛擬機就會在底層為我們創(chuàng)建出一個異常對象,從而將相關的異常信息打印輸出。

所以:

Java中異常是的的確確存在的類

Java的異常處理機制

接下來我們來說說Java的異常機制。我們還是來看上面那個代碼,也就是這個:

public static void main(String[] args) {
        int a = 1;
        int b = 0;
        System.out.println(a / b);
    }

這段代碼我們?nèi)绻\行的話是會出錯的,也就是這樣:

這里會給到我們一個異常信息,告訴我們說除數(shù)不能為0,然后程序就自動退出了,接下來我們再為這段代碼添加一個打印輸出:

很顯然這里并不會執(zhí)行后面的這句輸出語句,因為前面已經(jīng)出現(xiàn)異常程序退出了,但是如果我們要求這里的輸出必須執(zhí)行該怎么辦呢?

在Java中是提供了相對應的異常處理機制的,以上在a/b的時候出現(xiàn)了異常,在Java中我們是可以通過如下的方式去捕獲到這個異常的。

try-catch捕獲異常

具體的操作就是使用try- catch去捕獲我們的異常并作出相應處理,具體看代碼:

public static void main(String[] args) {

        int a = 1;
        int b = 0;
        try {
            System.out.println(a / b);
        } catch (Exception e) {
            System.out.println(e+":除數(shù)不能為0!");
        }
        
        System.out.println("執(zhí)行到這里……");
        
    }

我們在之前已經(jīng)說過,在Java中,異常是以類的形式存在的,在我們寫的程序代碼中,只要出現(xiàn)了異常,JVM就會給我們創(chuàng)建一個異常對象出來,這個時候,我們是需要對這個異常對象做處理的,如果你放任不管的話,最終導致的結果就是你的Java程序會退出。

所以啊,有異常你不處理,你的程序就會退出,那咋辦,處理啊,找到這個異常,處理它,那怎么找到呢?

我們可以使用try去包裹可能出現(xiàn)的異常代碼,比如上述所講的代碼,在執(zhí)行到a/b的時候可能出現(xiàn)異常,也就是b不能為0,這里簡單說下,這里的a和b是我們提前定義還好的,如果是讓用戶輸入a和b的值呢?

我們簡單改寫下代碼:

Scanner StringA = new Scanner(System.in);
        Scanner StringB = new Scanner(System.in);

        int a = Integer.parseInt(StringA.next());
        int b = Integer.parseInt(StringB.next());

        System.out.println(a/b);

        System.out.println("執(zhí)行到這里……");

這里的意思是我們從鍵盤輸入去獲取這個a和b,那么當我們輸入的是這樣的a和b的時候執(zhí)行是沒什么問題的:

可是一旦用戶不小心把b的值輸成0,那么問題就來了:

所以這里繞了一圈就是告訴大家b/a這步操作是可能出現(xiàn)異常的,我們把這個操作叫做可能出現(xiàn)的異常代代碼塊,于是我們就可以使用try去操作這段代碼:

    try {
            System.out.println(a / b);
        } catch (Exception e) {
            System.out.println(e+":除數(shù)不能為0!");
        }

這里要注意的就是,這個try和catch是一起配合使用的,catch是捕獲的意思,我們使用try包裹可能出現(xiàn)的異常代碼快,然后使用catch去捕獲這個異常對象,然后做出相應的處理,比如這里,我們使用try包裹了a/b的操作,那么當b不小心被賦值為零的時候,那么這里在運行的時候就會出現(xiàn)異常,由于在Java中異常是以類的形式存在,所以這里會拋出一個異常對象。

那么我們仔細看這個catch后面有個括號,就是異常對象參數(shù),意思就是如果出現(xiàn)的這個異常對象屬于我括號里的這個異常,那么就進入這個catch塊去處理這個異常。

說白了就是,程序一旦出現(xiàn)異常,隨之而來就是會產(chǎn)生一個異常對象,而異常是以類的形式存在,那么你就得為這個異常對象定義一個catch塊,這個異常對象會根據(jù)catch后的參數(shù)去找屬于自己的那一個catch塊,找到就進入該catch塊,沒有的話程序就有因為異常而終止了。

而除數(shù)為0這是一個叫做ArithmeticException的異常,也就是算術異常,而這個異常是繼承自Exception,也就是說Exception的范圍比ArithmeticException要大,所以Exception的catch塊可以處理身為子類的ArithmeticException異常。

異常類的繼承

以上我們說了ArithmeticException這個異常是繼承自Exception的,后者的范圍更廣,然后我們再看代碼:

        try {
            System.out.println(a / b);
        } catch (ArithmeticException e) {
            System.out.println(e + ":除數(shù)不能為0!出現(xiàn)算術異常");
        } catch (Exception e) {
            System.out.println(e+"出現(xiàn)異常");
        }

也就是說,一個try下面可以對應多個catch塊,而每一個catch都有自己對應的一個可以處理的異常類型,我們看上面的改進,我們添加了負責處理ArithmeticException的catch塊,那么結果是如呢?

可以看到,這里是直接進入了ArithmeticException的catch塊,也就是說,異常對象一旦被一個catch捕獲,就不會再進入下一個異常了。

有人可能會說可以這樣嗎?

也就是把Exception放在第一個catch塊,實際上這里是不行的,為啥?我們來看下再這里的一個異常繼承關系:

可以看到,ArithmeticException其實是Exception的子類的,如果你把Exception放在第一個catch塊的話那么所以的異常對象都將直接被這個catch塊捕獲,因為所有的異常對象都是Exception或者其子類的實例對象,這就很關鍵啊,意味著你后面定義再多的catch塊也沒有用啊,因為永遠不會執(zhí)行到這里,上面已經(jīng)被Exception這個老大哥給截胡了,在Java中永遠執(zhí)行不到的代碼就會被定義為錯誤的,所以是不能把Exception給放到第一個catch塊的。

這里有這么一個原則:

先捕獲處理小范圍的異常,再捕獲處理大范圍的異常,也就是先小后大

意思也就是先把子類異常放在前面的catch塊,這么以來,Exception的捕獲基本上都是在最后一個catch了。

多異常的處理

這個是在Java 7之后增加的,也就是說啊在Java7之前嘞,一般來說一個catch塊只能捕獲處理一個異常,但是在Java7之后就升級了,可以一個catch塊捕獲處理多個異常。

那這個是怎么操作的呢?來看看代碼就一目了然了:

是不是還是比較清楚的,這里的編寫也很簡單,就是通過符號“|”把不同的異常對象類型給分隔開,記住這里只需要在最后定一個異常就行,也就是這里的“e”,同時由于是捕獲多個異常,這里的e其實是默認final修飾的,因此就不能再對e進行任何賦值操作了,比如一下這樣就是錯誤的:

這就是多個異常的捕獲了。

獲取異常信息

先明白這點:

當產(chǎn)生一個異常對象,被相對應的catch塊捕獲之后,這個catch塊后的異常形參變量也就接受到了這個異常對象。

因此,我們就可以通過這個異常參數(shù)去獲得一些異常信息,一般我們常用的一些方法如下:

  • getMessage():這個方法會返回異常的詳細描述信息
  • printStackTrace():這個方法會打印出異常的跟蹤棧信息
  • printStackTrace(PrintStream p):這個則會將異常的跟蹤棧信息輸出到指定的輸出流中去
  • getgtacktreace():返回異常的跟蹤站信息

那具體的訪問,我們看下代碼便知:

這里其實也比較簡單,就是幾個常見的異常信息獲取方法的使用。

finally

這個可以說叫做善后的,啥意思嘞?簡單來說,就是你的異常對象無論進入哪個catch塊執(zhí)行,那么到最后這個finally里的代碼一定會被執(zhí)行。

這個一般用在哪里呢?通常被用于釋放資源,一般比如說數(shù)據(jù)庫連接操作,網(wǎng)絡連接或者常見的IO流的操作,這些就需要進行資源的回收,那么這個時候就可以使用finally里,因為它必定會被執(zhí)行。

看到這里不知道大家有沒有疑惑啊,不是說Java會自動回收資源嗎?這個感覺要手動操作啊,這里其實你要區(qū)分資源的分類,Java的垃圾回收針對的堆內(nèi)存中的對象所占用的內(nèi)存,而這里說的IO流操作,數(shù)據(jù)庫連接什么都是屬于物理資源,而物理資源必須是需要手動回收的。

看看代碼:

這個時候我們看異常的處理就比較完整了,也就是包括try,然后是catch,再加上一定會被執(zhí)行的finally塊。

那么這里就需要特別說一下了:

對于異常處理來說,try塊是必須的,沒有try塊啥也不是,而catch和finally則不是必須的,但是,也必須選擇其一,也就是說,你不能只有個try,既沒有catch也沒有finally,然后就是注意catch塊了,可以有多個,但是要遵循“先小后大”的原則

接下來我們來看個測試,看代碼:

我們在這里加入了return語句,一般來說吧,只要程序的方法中碰到了return,那么就會立即結束該方法,但是現(xiàn)在呢?我們看下結果:

這說明,finally語句一定會被執(zhí)行!另外再給大家說一個注意點:

如果你在finally中定義了return語句,那么這個將導致你在try中定義的return語句失效,所以記住一點,不要在finally中使用return哦。

到這里我們清楚了,對于finally語句來說是一定會被執(zhí)行的(其實有例外,比如你調用了System.exit(1)退出虛擬機),我們常在finally中去做釋放資源的操作,但是你有沒有發(fā)現(xiàn),這樣的操作覺得比較麻煩😡,那有沒有簡單的一些做法呢?

其實在Java7中對這個try語句進行了增強,可以讓我們不需要在finally中進行資源的關閉操作,可以自動幫我們關閉需要釋放的資源,但是這里有個前提就是你所需要關閉的資源類要么實現(xiàn)AutoCloseable接⼝,要么實現(xiàn)Closeable接⼝,實際上在Java7中幾乎把所有的資源類都進行了改寫,主要就是都實現(xiàn)了AutoCloseable或者Closeable接⼝,可以讓其實現(xiàn)資源的自動關閉,這些資源類一般就是文件IO的各種類,或者是JDBC的Connection接口等等。

那到了Java9之后又對這個try語句進行了增強,在java7的改進中你需要在try后的圓括號內(nèi)聲明并創(chuàng)建資源,到了Java9,你不需要這樣做了,只需要自動關閉的資源有final修飾或者是有效的final即可,這里先盡做了解,后期會詳細探討。

Checked異常和Runtime異常

接下來我們來看看關于異常的分類,Java中的異??梢苑譃閮蓚€大類:

  • Checked異常
  • Runtime異常

那怎么區(qū)分這兩類異常呢?所有的RuntimeException類及其⼦類的實例被稱為Runtime異常;不 是RuntimeException類及其⼦類的異常實例則被稱為Checked異常。

那對于Checked異常就是可檢查異常,也就是說在Java中認為這種異常是可以被提前處理的,所以一旦出現(xiàn)這種異常你就得處理它,如果不處理它,那是編譯都無法通過的。

那怎么去處理這個Checked異常呢?我們前面也說了,可以使用try- catch的方式去捕獲處理異常,當然,我們還有一種方式就是拋出異常,暫且不管,這個等會會講。

對于Runtime異常也就是運行時異常了,這個我們不需要在編譯階段就處理它,如果要處理的話,可以使用try- catch,就比如上面我們一直演示的那個除數(shù)為0的案例。

throws

我們可以使用throws來聲明拋出異常,啥意思嘞,這個拋出異常咋回事?字面意思去理解,就是這個異常不管了,扔出去,對吧,拋出拋出,那如何扔出去呢?使用這個throws關鍵字即可。

也就是說當你不知道該如何處理某一類型的異常的時候,你就可以選擇將該異常拋出,實際上拋出異常也不是說就不管異常了,而是將該異常交給上一級調用者去處理。如果一直往上拋出異常,最終就把這個燙手山芋交給了JVM,那JVM是怎么處理這個異常呢?

一般就是:

打印異常的跟蹤棧信息,并中止程序

下面我們來看下代碼:

我們這里在main方法上使用throws拋出了這個異常,那就是把這個異常扔給了我們的JVM,而JVM的處理上面也說了,我們看下結果:

打印出跟蹤棧信息,然后中止程序,這里其實是個運行時異常,也就是Runtime異常,接下來我們看下對于Checked異常的拋出,我們首先編寫一段含有Checked異常的代碼,如下:

這里就會產(chǎn)生一個編譯時異常,那么IDEA給我們的提示可以用try/catch捕獲處理,當然,也可以使用throws關鍵字拋出,我們這里將其拋出:

接下來我們在main方法中去調用這個方法:

發(fā)現(xiàn)了嗎?我們在main方法中調用它依然是需要處理出現(xiàn)的異常的,本身CheckedTest將異常拋出,就是希望由調用者去處理該異常,所以這里我們在main方法中去調用該方法的時候也要一并去處理該方法產(chǎn)生的異常,要不你繼續(xù)將其拋出交給JVM,要不使用try/catch捕獲!

Checked異常的限制

這里給大家看一個示例:

發(fā)現(xiàn)沒有,當我們使用throws去拋出一個異常時,父類中的方法拋出一個異常,而其子類中重寫該父類拋出異常的方法的時候,重寫后的方法拋出的異常的范圍是不能比父類中方法拋出的異常的范圍大的,這句話可能有點繞,但是配合看圖應該能明白什么意思。

這其實就是Checked異常所帶來的一個限制。

手動拋出異常

以上我們使用throw是來拋出異常其實都是Java自動幫我們?nèi)伋霎惓ο蟮?,除此之外,我們還可以自己手動的去拋出異常,這里需要使用到的一個關鍵字叫做throw,注意這里是沒有s的,和以上我們說的throws是不一樣的。

想一下這里為什么要手動拋出異常呢?因為異常本身就不是確定的,什么意思呢?就是同一件事情,在不同的人看來可能性質就不一樣,比如你明天要外出,可是明天突然就下雨了,那么這個下雨對你來說就是一種異常,是你不想要的,但是對于那些尤為某種情況希望明天下雨的來說,這件事情就不是一件異常事件。

對應到我們的程序中,異常也是要根據(jù)具體情況來定義的,因此這種異常是系統(tǒng)無法幫我們來判定的,這就需要我們自行去拋出異常。

具體就是使用throw來手動拋出異常,怎么操作的看代碼:

try {
            //規(guī)定第一次輸入的值不能大于10,也就是這里的stringA不能大于10
            Scanner stringA = new Scanner(System.in);
            Scanner stringB = new Scanner(System.in);
            int a = Integer.parseInt(stringA.next());
            int b = Integer.parseInt(stringB.next());

            if (a > 10) {
                throw new Exception("輸入的第一個數(shù)字不能大于10");
            } else {
                System.out.println(a + b);
            }
        } catch (Exception e) {
    		System.out.println(e.getMessage());
            System.out.println("第一次輸入請輸入一個小于10的數(shù)字!");
        }

同樣的,當你手動的拋出一個異常的時候也是需要對這個異常進行處理的,我們這里使用try/catch來捕獲處理該異常,看結果:

這里說一點,就是無論你是手動拋出異常還是系統(tǒng)給我們拋出異常,在java中對異常的處理方式是不變的。也就是說碰到Checked異常,要不使用throws將其拋出,要么使用try/catch語句塊捕獲處理。

自定義異常

一般來說吧,我們不會去手動拋出異常,當然,這里說的異常指的是系統(tǒng)級別的異常,那除此之外,我們還可以自己自定義異常,代碼如下:

class MyException extends Exception {
    public MyException(){}

    public MyException(String msg) {
        super(msg);
    }
}

以上我們就自定義了一個異常,自定義異常我們需要注意以下兩點:

創(chuàng)建一個無參構造器創(chuàng)建一個帶有字符串參數(shù)的有參構造器

這里的字符串參數(shù)其實就是異常的具體描述信息,比如我們之前這樣定義一個異常:

一般的我們要是自定義異常的話最好就是有一個“見名知意”的程度,就是我看到你這個自定義異常類名,大概知道這是一個什么異常。

小結

以上我們就Java中的異常進行了學習,不知道你發(fā)現(xiàn)沒有,我們對異常的學習其實主要就是在圍繞以下五個關鍵字:

trycatchfinallythrowsthrow

然后還有就是要注意Checked異常和Runtime異常,以上都是關于異常的基本知識,掌握這些,足以應付我們在日常工作學習中異常操作,至于更深層次的學習則需要我們在實際應用的去不斷的探索了,關于Java中的異常,我們就先介紹到這里。

到此這篇關于Java異常的文章就介紹到這了,更多相關Java異常內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 關于Spring的AnnotationAwareAspectJAutoProxyCreator類解析

    關于Spring的AnnotationAwareAspectJAutoProxyCreator類解析

    這篇文章主要介紹了關于Spring的AnnotationAwareAspectJAutoProxyCreator類解析,Spring是一個開源免費的框架 , 容器,是一個輕量級的框架 ,需要的朋友可以參考下
    2023-05-05
  • Java后臺接收數(shù)據(jù)的三種方式(url、form-data與application/json)

    Java后臺接收數(shù)據(jù)的三種方式(url、form-data與application/json)

    本文主要介紹了Java后臺接收數(shù)據(jù)的三種方式(url、form-data與application/json),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-07-07
  • Java實現(xiàn)Html轉Pdf的方法

    Java實現(xiàn)Html轉Pdf的方法

    這篇文章主要介紹了Java實現(xiàn)Html轉Pdf的方法,實例分析了java基于ITextRenderer類操作頁面及系統(tǒng)自帶字體生成pdf文件的相關技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-07-07
  • java實現(xiàn)從方法返回多個值功能示例

    java實現(xiàn)從方法返回多個值功能示例

    這篇文章主要介紹了java實現(xiàn)從方法返回多個值功能,結合實例形式分析了集合類、封裝對象、引用傳遞三種實現(xiàn)方法,需要的朋友可以參考下
    2017-10-10
  • Java多線程、進度條實現(xiàn)賽馬實驗的示例代碼

    Java多線程、進度條實現(xiàn)賽馬實驗的示例代碼

    這篇文章主要介紹了Java多線程、進度條實現(xiàn)賽馬實驗的示例代碼,代碼簡單易懂,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • Java使用FFmpeg處理視頻文件的方法教程

    Java使用FFmpeg處理視頻文件的方法教程

    這篇文章主要給大家介紹了關于Java使用FFmpeg處理視頻文件的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-03-03
  • springboot如何根據(jù)不同的日志級別顯示不同的顏色

    springboot如何根據(jù)不同的日志級別顯示不同的顏色

    這篇文章主要介紹了springboot如何根據(jù)不同的日志級別顯示不同的顏色問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • JVM回收跨代垃圾的方式詳解

    JVM回收跨代垃圾的方式詳解

    在Java堆內(nèi)存中,年輕代和老年代之間存在的對象相互引用,假設現(xiàn)在要進行一次新生代的YGC,但新生代中的對象可能被老年代所引用的,為了找到新生代中的存活對象,不得不遍歷整個老年代,這樣明顯效率很低下,那么如何快速識別并回收這種引用對象呢
    2024-02-02
  • Java的LinkedHashMap的實現(xiàn)原理詳解

    Java的LinkedHashMap的實現(xiàn)原理詳解

    這篇文章主要介紹了Java的LinkedHashMap的實現(xiàn)原理詳解,???LinkedHashMap是Map接口的哈希表和鏈接列表實現(xiàn),具有可預知的迭代順序,此實現(xiàn)提供所有可選的映射操作,并允許使用null值和null鍵,此類不保證映射的順序,特別是它不保證該順序恒久不變,需要的朋友可以參考下
    2023-09-09
  • 基于Java中進制的轉換函數(shù)詳解

    基于Java中進制的轉換函數(shù)詳解

    下面小編就為大家?guī)硪黄贘ava中進制的轉換函數(shù)詳解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-07-07

最新評論