1. 程式人生 > >雜談——執行時異常和普通異常有什麼區別

雜談——執行時異常和普通異常有什麼區別

說到異常,大家都熟悉,只要程式出錯了,那麼肯定會說:“哎呀,我的程式出錯啦~它丟擲異常啦”。

但單單以“異常”的名稱來稱呼它們,未免也太粗糙了。我們畢竟是一個精緻的程式設計師,當然得知道他們到底都有哪些種類啦。這就好比一個優質的男朋友(比如本帥博主)必須能夠精準地區分女朋友的口紅色號一般。

那Java到底有哪些異常呢?

其實也不多,Java提供了兩種錯誤的異常類,分別是Error和Exception,它們的爸爸(即父類)都是Throwable,從這個角度來看,它們也算的上是親兄弟啦。

但哪怕是兄弟,那也會有差別。那麼咱們就來看看這兩兄弟都有區別。

1.Error

Error,看名字就知道,這個錯誤肯定不會小,事實上也的確是如此,Error表示程式在執行期間出現了非常嚴重的錯誤,並且該錯誤是不可恢復的。

這個錯誤到底有多嚴重呢?“Error屬於JVM層次的錯誤”。

JVM我們都知道,程式碼的順利執行時離不開JVM這位大佬的。當JVM層次出現錯誤,那鐵定會導致程式終止執行。此外,編譯器不會檢查Error是否被處理了,所以呀,在程式中我們不推薦去捕獲Error型別的異常,主要的原因就是執行時異常大多都是邏輯錯誤導致的,它屬於應該解決的錯誤,也就是說,一個正常的程式中式不應該存在Error的。像我們平常經常遇見的OutOfMemoryError、ThreadDeath等都是屬於Error的,當這些錯誤發生的時候,JVM基本上都會選擇讓程式終止。

怎麼理解上面的話呢,舉個例子。假如咱們在面試的時候,和麵試官爆發了語言上乃至身體上的衝突,這種錯誤就是Error,出現這種錯誤,面試鐵定得中斷了呀,毫無疑問的,咱們這次面試肯定也就涼涼了。對方不需要知道你在這件事情發生之後有沒有進行反省或者挽救,反正你這回面試就是涼了,再怎麼補救都沒有用。我們只能放棄這次面試,改過自新,爭取在下一次面試的時候不再出現這樣的Error,這樣才有可能讓面試順利進行,而不被中斷。

所以呀,無論是寫程式碼還是做別的事情,咱們都得謹慎,因為一旦出現了Error,無論咱們怎麼補救,對本次程式執行或者事情都是無濟於事的。

2.Exception

上面說到Error是一個超級重大的錯誤,那麼作為它的兄弟,或多或少在這一方面會對Error的強硬有一些彌補。

Exception表示的是可恢復的異常,是編譯器可以捕捉到的,而這傢伙有包含這兩種型別:檢查異常惡化執行時異常。

(1)檢查異常

檢查異常是在程式中最經常碰到異常,所有繼承自Exception並且不是執行時異常的異常都是檢查異常,比如咱們最常見的IO異常和SQL異常。這種異常都發生在編譯的階段,Java編譯器強制程式去捕獲此型別的異常,即它會把可能會出現這些異常的程式碼放到try塊中,把對異常的處理程式碼放到catch塊中。這種異常一般在如下幾種情況中使用:

  • 異常的發生並不會導致程式出錯,進行處理之後可以繼續執行後續的操作,比如,連線資料庫失敗之後可以重新連線之後再進行後續操作。
  • 程式依賴於不可靠的外部條件,比如系統IO。

(2)執行時異常

執行時異常不同於檢查異常,編譯器沒有強制對其進行補貨並處理,如果不對異常進行處理,那麼當出現這種異常的時候,會由JVM來處理,比如NullPointerException異常,它就是執行時異常。

在Java語言中,最常見的執行時異常包括NUllPointerException(空指標異常)、ClassCastException(型別轉換異常)、ArrayIndexOutOfBoundsException(陣列越界異常)、ArrayStoreException(陣列儲存異常)、BufferOverflowException(緩衝區溢位異常)、ArithmeticException(算術異常)等。

出現執行時異常之後,系統一般會把異常一直往上層拋,知道遇到處理程式碼位置,如果沒有處理程式碼,那就一直拋到最上層;如果是多執行緒就會用Thread.run()的方法丟擲;如果是單執行緒就用main()方法丟擲。丟擲之後呢,如果是執行緒,那麼這個執行緒也就退出了,如果是主程式丟擲的異常,那麼這個主程式也就退出了。所以說,如果不對執行時的異常進行處理,後果也是非常嚴重的,一旦發生這種異常,要麼是執行緒中止,要麼就是主程式終止。

不過,在進行異常處理的時候,還需要注意一下幾個問題:

(2.1)Java異常處理用到了多型的概念,如果在異常處理過程中,先捕獲到了基類,然後再捕獲子類,那麼捕獲子類的程式碼永遠都不會被執行。因此,在進行以後才那個捕獲的時候,正確的方法是先捕獲子類,然後再捕獲基類的異常資訊。

錯誤示例如下:

try{
    //access db code
}catch(Exception e2)
{
    //deal with this exception
}catch(SQLException e1)

那要怎麼寫呢,如下: 

try{
    //access db code
}catch(SQLException e1)
{
    //deal with this exception
}catch(Exception e2)

(2.2)我們要儘早地丟擲異常,同時對捕獲的異常異性處理,或者從錯誤中恢復,或者讓程式繼續執行。咱們程式設計師得時刻記住,對捕獲的異常不進行處理是一個非常不好的一貫,這樣將非常不利於除錯。但是,也不是丟擲的異常越多越好,對於有些異常,比如執行時異常,實際上根本不必處理。

(2.3)可以根據實際的需求自定義一場類,這些自定義的一場類只要是繼承自Exception類即可。

(2.4)異常能處理就處理,不能處理就跑出,對於一般一場來說,如果不能進行有效的處理,最好轉換成為執行時異常丟擲。而對於最終沒有被處理的異常,JVM會進行處理。

關於檢查異常和執行時異常,我們來看一個例子:

public class ExceptionTypeTest {
	public void doSomething()throws ArithmeticException
	{
		System.out.println("this is doSomething");
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		ExceptionTypeTest ett=new ExceptionTypeTest();
		ett.doSomething();
	}
}

大家猜猜,這段程式可以編譯通過嗎?

我們來試一試。

 

上圖表示這是可以的。那麼,如果咱們更換一下異常的種類,將ArithmeticException換成IOException異常呢?

可以看到程式碼會提示錯誤。如果強行執行的話,將報錯,如下圖。

為什麼ArithmeticException可以編譯通過,而IOException不可以呢?因為前者屬於執行時異常,編譯器沒有強制對其進行捕獲並處理,因此編譯可以通過。而IOException屬於檢查異常,編譯器會強制去捕獲此型別的異常,如果不對異常進行捕獲的話將會有編譯錯誤。

因此,我們只要捕獲一下異常就可以了 用try-catch或者throws即可。如下圖:

方法一:

方法二:

執行結果如下:

3.總結

 Error:是JVM(java虛擬機器)中出現的不可恢復的錯誤。
 Exception:是類發生的異常,又具體分為以下三種:

  •    檢查異常:  編譯期發生
  •    執行時異常: 執行期(執行時)發生
  •    自定義異常

總而言之,對於異常,需謹慎,切記喲~。

好啦,以上就是關於執行時異常和普通異常的相關知識總結啦,如果大家有什麼不明白的地方或者發現文中有描述不好的地方,歡迎大家留言評論,我們一起學習呀。

 

Biu~~~~~~~~~~~~~~~~~~~~宫å´éªé¾ç«è¡¨æå|é¾ç«gifå¾è¡¨æåä¸è½½å¾ç~~~~~~~~~~~~~~~~~~~~~~pia!