聊聊Java的異常機制問題

摘要:java異常指在程序運行時可能出現的一些錯誤,如:文件找不到、網絡鏈接失敗、非法參數等。異常是一個事件,它發生在程序運行期間,中斷了正在執行的程序的正常指令流。

本文分享自華爲雲社區《Java知識點問題精選之異常機制》,原文做者:breakDraw 。java

java異常指在程序運行時可能出現的一些錯誤,如:文件找不到、網絡鏈接失敗、非法參數等。異常是一個事件,它發生在程序運行期間,中斷了正在執行的程序的正常指令流。程序員

Java經過API中Throwable類的衆多子類描述各類不一樣的異常。於是,Java異常都是對象,是Throwable子類的實例,描述了出如今一段編碼中的錯誤條件。當條件生成時,錯誤將引起異常。對於運行時異常、錯誤或可查異常,Java技術所要求的異常處理方式有所不一樣。segmentfault

異常體系分類

Q: Throwable 和 Error的關係
A: Throwable是Error(錯誤)的基類,也是Exception的基類
1個好圖,可看到常見的異常和error網絡

Q: Error和Exception的關係
A:jvm

  • Error通常是會直接引發jvm出錯的錯誤,例如Java虛擬機運行錯誤等,若是出現了當前線程會沒法繼續運行。
  • Excpetion是程序自己能夠處理的異常。發生後還能正常運行。

Q: Error能夠被catch捕捉嗎?
A: 只要是Throwable和其子類都是能夠throw和catch的。 可是不建議捕捉Error。ide

異常體系還能夠分爲這2類:編碼

  • unchecked exception(非檢查異常)
    也稱運行時異常(RuntimeException),好比常見的NullPointerException、IndexOutOfBoundsException。對於運行時異常,java編譯器不要求必須進行異常捕獲處理或者拋出聲明,由程序員自行決定。
  • checked exception(檢查異常,編譯異常)
    也稱非運行時異常(運行時異常之外的異常就是非運行時異常),java編譯器強制程序員必須進行捕獲處理,好比常見的IOExeption和SQLException。對於非運行時異常若是不進行捕獲或者拋出聲明處理,編譯都不會經過。

異常捕捉和返回

Q: return-finally陷阱1: finally能經過修改變量,來更新return的變量值嗎spa

int f() {
  int a = 1;
  try {
      return a;
  }
  finally {
      a=2;
  }
}

A: 不能, f返回1。線程

Q: return-finally陷阱2: finally裏也return時,返回哪一個?code

int f() {
  try {
      return 1;
  }
  finally {
      return 2;
  }
}

A:返回finally裏的,返回2。

Q: 什麼狀況下finally塊裏的步驟能夠不執行?
A: 只有在finally以前調用System.exit(0)退出jvm, 才能讓finally不執行。

Q: 下面會發生什麼?

try {
    start();
} catch (Exception ex) {
    System.out.println("catch Exception");
} catch (RuntimeException re) {
    System.out.println("catch RuntimeException");
}

A: 直接編譯就錯誤了。 catch是會按順序的且匹配1個就再也不往下匹配,編譯器所以識別出RuntimeExcpetion永遠不會被捕捉到,便提早報錯。

Q:throw異常的時候,在finally中作return,那麼異常還會拋出嗎?

static int f() {
    try {
        int a = 1/0;
        return a;
    } catch (Exception e) {
        throw new RuntimeException(e);
    } finally {
        return -1;
    }
}
public static void main(String[] args) {
    System.out.println(f());
}

A:不會,返回-1.

即finaly中作return會中斷throw
所以永遠不要在finally中去作return操做

受檢異常相關問題

Q: 子類覆寫基類方法時 , 能throws基類方法中不存在的異常嗎?
像下面這樣:

class A{
    void f() throws IOException{
    }
}
class B extends A{
    void f() throws IOException, SQLException {
    }
}

A: 不行,直接編譯報錯。 即子類覆寫父類方法時, throws關鍵字後面跟的異常必須是小於等於父類方法異常的。

Q: finally中調用某資源的close時,也會拋出受檢異常, 除了在finally裏作try-catch,還能怎麼作?

像下面這樣,finally又有catch,就很難看:

TryWithResource tryWithResource = new TryWithResource();
        try {
            System.out.println(tryWithResource.age);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                tryWithResource.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

A:若是是JDK1.7,能夠用try-with-resource語法。

須要資源類實現AutoCloseable接口, 並在try的時候在try括號後面跟上資源的建立,以下:

public static void main(String[] args) {
        try (TryWithResource tryWithResource = new TryWithResource()) {
            System.out.println(tryWithResource.age);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

這樣就不須要寫finally,finally+close會經過編譯器給咱們自動加上。

Q: 線程拋出異常的話該怎麼捕捉?

A: 實現異常處理接口MyUnchecckedExceptionhandler

public class MyUnchecckedExceptionhandler implements UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("捕獲異常處理方法:" + e);
    }
}

而後把實現類設置給對應線程。

Thread t = new Thread(new ExceptionThread());
t.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
t.start();

點擊關注,第一時間瞭解華爲雲新鮮技術~

相關文章
相關標籤/搜索