1. 程式人生 > 程式設計 >非常全面的Java異常處理(全文乾貨,值得收藏)

非常全面的Java異常處理(全文乾貨,值得收藏)

一.初始Java異常

1、對異常的理解:異常:在Java語言中,將程式執行中發生的不正常情況稱為“異常”。(開發過程中的語法錯誤和邏輯錯誤不是異常)

2、Java程式在執行過程中所發生對異常事件可分為兩類:

  • Error:Java虛擬機器無法解決的嚴重問題。如:JVM系統內部錯誤、資源耗盡等嚴重情況。比如:StackOverflowError和OOM。一般不編寫針對性 的程式碼進行處理。
  • Exception: 其它因程式設計錯誤或偶然的外在因素導致的一般性問題,可以使用針對性的程式碼進行處理。例如:
  • 空指標訪問
  • 試圖讀取不存在的檔案
  • 網路連線中斷
  • 陣列角標越界

3、執行時異常和編譯時異常

執行時異常

  • 是指編譯器不要求強制處置的異常。一般是指程式設計時的邏輯錯誤,是程式設計師應該積極避免其出現的異常。java.lang.RuntimeException類及它的子類都是執行時異常。
  • 對於這類異常,可以不作處理,因為這類異常很普遍,若全處理可能會對程式的可讀性和執行效率產生影響。

編譯時異常

  • 是指編譯器要求必須處置的異常。即程式在執行時由於外界因素造成的一 般性異常。編譯器要求Java程式必須捕獲或宣告所有編譯時異常。
  • 對於這類異常,如果程式不處理,可能會帶來意想不到的結果。

在這裡插入圖片描述

二.Error和Exception

1.Error

程式碼示例一:java.lang.OutOfMemoryError(堆溢位)

public class ErrorTest {
 public static void main(String[] args) {
 //堆溢位:java.lang.OutOfMemoryError
 Long[] arr = new Long[1024*1024*1024];
 }
}

執行結果:

在這裡插入圖片描述

程式碼示例二:java.lang.StackOverflowError(棧溢位)

public class ErrorTest {
 public static void main(String[] args) {

 //棧溢位:java.lang.StackOverflowError
 main(args);
 }
}

執行結果:

在這裡插入圖片描述

2.Exception(執行時異常和編譯時異常)

執行時異常

 /* ******************以下是執行時異常****************** */
 //ArithmeticException
 @Test
 public void test1(){
 int num1 = 3;
 int num2 = 0;
 int num3 = 3 / 0;
 }

 //InputMismatchException
 @Test
 public void test2(){
 Scanner scanner = new Scanner(System.in);
 int i = scanner.nextInt();
 System.out.println(i);
 scanner.close();
 }

 //NumberFormatException
 @Test
 public void test3(){
 String str = "abcd";
 int num = Integer.parseInt(str);
 }

 //ClassCastException
 @Test
 public void test4(){
 Object obj = new Boolean(true);
 String str = (String)obj;
 }

 //IndexOutOfBoundsException
 @Test
 public void test5(){
 ArrayIndexOutOfBoundsException
 Byte[] bytes = new Byte[3];
 System.out.println(bytes[4]);
 }

 //NullPointerException
 @Test
 public void test6(){
 int[] arr = null;
 System.out.println(arr[1]);
 }

編譯時異常

/* ******************以下是編譯時異常****************** */
 @Test
 public void test7(){
 File file = new File("a.txt");
 //java.io.FileNotFoundException
 FileInputStream fis = new FileInputStream(file);
 //java.io.IOException
 int date = fis.read();
 while (date != -1){
  System.out.println((char)date);
  date = fis.read();
 }

 fis.close();
 }

ps:對於編譯時異常,我們需要異常處理

三.異常處理:抓拋模型

1.抓拋解釋

過程一:“拋”:程式在正常執行的過程中,一旦出現異常,就會在異常程式碼處生成一個對應異常類的物件, 並將此物件丟擲;一旦丟擲物件以後,其後的程式碼就不再執行。

關於異常物件的產生:

① 系統自動生成的異常物件

② 手動的生成一個異常物件,並丟擲(throw)

過程二:“抓”:可以理解為異常的處理方式:① try-catch-finally ② throws

2.try-catch-finally的使用

try{
//可能出現異常的程式碼

}catch(異常型別1 變數名1){
//處理異常的方式1
}catch(異常型別2 變數名2){
//處理異常的方式2
}catch(異常型別3 變數名3){
//處理異常的方式3
}
…
finally{
//一定會執行的程式碼
}

說明:

  1. finally是可選的。
  2. 使用try將可能會出現異常的程式碼段包裝起來,在執行過程中,一旦出現異常,就會生成一個對應異常類的物件,根據此物件的型別,去catch中進行匹配
  3. 一旦try中的異常物件匹配到某一個catch時,就進入catch中進行異常的處理。一旦處理完成,就跳出當前的
    try-catch結構(在沒有寫finally的情況)。繼續執行其後的程式碼
  4. catch中的異常型別如果沒有子父類關係,則誰宣告在上,誰宣告在下無所謂。
    catch中的異常型別如果滿足子父類關係,則要求子類一定宣告在父類的上面。否則,報錯
  5. 常用的異常物件處理的方式: ① String getMessage() ② printStackTrace()
  6. 在try結構中宣告的變數,再出了try結構以後,就不能再被呼叫
  7. try-catch-finally結構可以巢狀
  8. finally中宣告的是一定會被執行的程式碼。即使catch中又出現異常了,try中有return語句,catch中有return語句等情況。
  9. 像資料庫連線、輸入輸出流、網路程式設計Socket等資源,JVM是不能自動的回收的,我們需要自己手動的進行資源的釋放。此時的資源釋放,就需要宣告在finally中。

示例一:

@Test
public void test1(){
 String str = "abcd";
 int num = 1314;
 try {
 num = Integer.parseInt(str);

 System.out.println("進入try程式碼塊!");
 }catch (NumberFormatException e){
 System.out.println("出現數值轉換異常了!");
 System.out.println(e.getMessage());
 e.printStackTrace();
 System.out.println("該catch語句塊將要執行完了!");
 } catch (NullPointerException e){
 System.out.println("出現空指標異常!");
 } catch (Exception e){
 System.out.println("出現異常了");
 }finally {
 System.out.println("執行finally語句了!");
 }
 System.out.println(num);
}

輸出結果:

在這裡插入圖片描述

示例二:

 @Test
 public void test2(){
  File file = new File("a.txt");
  FileInputStream fis = null;
  try {
   fis = new FileInputStream(file);
   int date = fis.read();
   while(date != -1){
    System.out.println((char)date);
    date = fis.read();
   }


  } catch (FileNotFoundException e) {
   e.printStackTrace();
  }catch (IOException e){
   e.printStackTrace();
  }finally {
   System.out.println("執行finally語句了!");
   try {
    fis.close();
   } catch (IOException e) {
    e.printStackTrace();
   }
  }
 }

輸出結果:

在這裡插入圖片描述

總結:

  • 使用try-catch-finally處理編譯時異常,是得程式在編譯時就不再報錯,但是執行時仍可能報錯。相當於我們使用try-catch-finally將一個編譯時可能出現的異常,延遲到執行時出現。
  • 開發中,由於執行時異常比較常見,所以我們通常就不針對執行時異常編寫try-catch-finally了。針對於編譯時異常,我們說一定要考慮異常的處理。

3.throws + 異常型別的使用

"throws + 異常型別"寫在方法的宣告處。指明此方法執行時,可能會丟擲的異常型別。一旦當方法體執行時,出現異常,仍會在異常程式碼處生成一個異常類的物件,此物件滿足throws後異常型別時,就會被丟擲。異常程式碼後續的程式碼,就不再執行!

try-catch-finally:真正的將異常給處理掉了。
throws的方式只是將異常拋給了方法的呼叫者。 並沒有真正將異常處理掉。

子類重寫的方法丟擲的異常型別不大於父類被重寫的方法丟擲的異常型別(子類重寫的方法也可以不丟擲異常)

public class SuperClass {
 public void method() throws IOException {

 }
}

class SubClass extends SuperClass{
 //報錯,子類重寫的方法丟擲的異常型別不大於父類被重寫的方法丟擲的異常型別
// public void method() throws Exception{
//
// }

 public void method() throws FileNotFoundException{

 }
}

開發中如何選擇使用try-catch-finally 還是使用throws? 如果父類中被重寫的方法沒有throws方式處理異常,則子類重寫的方法也不能使用throws,意味著如果

子類重寫的方法中有異常,必須使用try-catch-finally方式處理。執行的方法a中,先後又呼叫了另外的幾個方法,這幾個方法是遞進關係執行的。我們建議這幾個方法使用throws

的方式進行處理。而執行的方法a可以考慮使用try-catch-finally方式進行處理。

程式碼示例:

public class ErrorThrows {
 public static void method1() throws IOException {
  File file = new File("a.txt");
  FileInputStream fileInputStream = new FileInputStream(file);
  
  int data = fileInputStream.read();
  while(data != -1){
   System.out.println((char)data);
   data = fileInputStream.read();
  }
  fileInputStream.close();
 }
 
 public static void method2() throws IOException {
  method1();
 }
 
 public static void method3() throws IOException {
  method1();
 }

 public static void main(String[] args) {
  try {
   method3();
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
}

4.手動丟擲一個異常類物件(throw關鍵字使用)

程式碼示例:

public class ReturnException {
 static void method1(){
  try{
   System.out.println("進入方法1");
   throw new RuntimeException("手動丟擲異常");
  }catch (Exception e){
   e.printStackTrace();
   System.out.println(e.getMessage());
  } finally {
   System.out.println("執行finally語句了!");
  }
 }

 public static void main(String[] args) {
  method1();
 }
}

輸出結果:

在這裡插入圖片描述

四.自定義異常類

自定義異常類,有如下三步驟:

  • 繼承於現有的異常結構:RuntimeException 、Exception
  • 提供全域性常量:serialVersionUID
  • 提供過載的構造器

自定義異常類:

public class MyExceptionClass extends Exception{

 static final long serialVersionUID = -5641210210148784L;

 public MyExceptionClass() {
 }

 public MyExceptionClass(String message) {
  super(message);
 }
}

手動丟擲上述自定義的異常類物件:

public class MyExceptionTest {

 static void method1() throws MyExceptionClass {
  Scanner scanner = new Scanner(System.in);

  System.out.println("請輸入大於0的資料:");
  double next = scanner.nextDouble();
  if(next >0){
   System.out.println("您輸入的資料為:"+next);
  }else {
   throw new MyExceptionClass("您輸入的資料不滿足要求!");
  }
 }

 public static void main(String[] args) {
  try {
   method1();
  } catch (MyExceptionClass myExceptionClass) {
   myExceptionClass.printStackTrace();
  }
 }
}

執行結果:

在這裡插入圖片描述

到此這篇關於非常全面的Java異常處理的文章就介紹到這了,更多相關Java異常處理乾貨內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!