1. 例外情況

>

終於,程序員想到了標準化和自動化錯誤處理。這發生在異常被發明的時候。現在異常機制處理了80%的異常情況。

如果某個學者提出例外,那很可能是他或她的博士論文的主題。如果一個程序員想到了它,那麼他可能會從同事那裡得到一個友好的拍拍:“看起來不錯,兄弟。”

當 Java 程序中出現錯誤時,例如除法0,會發生一些奇妙的事情:

步驟1

創建一個特殊的異常對象,其中包含有關發生的錯誤的信息。

Java 中的一切都是對象,異常也不例外🙂Exception 對像有自己的類,唯一區別於普通類的是它們繼承了類Throwable

第二步

異常對像被“拋出”。也許這裡的措辭會更好。“拋出異常”更像是觸發火警或發出“DEFCON 1”警報。

當 Java 機器拋出異常時,程序的正常運行停止,“緊急協議”開始。

第三步

拋出異常的方法立即退出。異常被傳遞給調用方法,該方法也立即退出。依此類推,直到main方法退出。當main方法終止時,程序也終止。

例子:

代碼 控制台輸出
class Solution
{
   public static void main(String[] args)
   {
      System.out.println("Your attention, please! Preparing for the end of the world");
      endTheWorld();
      System.out.println("The world ended successfully");
   }

   public static void endTheWorld()
   {
      System.out.println("We're doing something important");
      doSomeWork(0);
      System.out.println("Everything is working well");
   }

   public static void doSomeWork(int n)
   {
      System.out.println("Nothing terrible will happen: " + n);
      System.out.println(2 / n);
      System.out.println("Nothing terrible happened: " + n);
   }
}
Your attention, please! Preparing for the end of the world
We're doing something important
Nothing terrible will happen: 0

第 20 行發生異常:除以 0。Java機器立即創建異常——一個ArithmeticException對象並將其“拋”給方法。

方法divide()立即結束,所以我們永遠不會看到字符串:Nothing terrible happened: 0。程序返回到方法endTheWorld(),情況重複:系統中出現未處理的異常,這意味著方法endTheWorld()也異常終止。然後該main方法終止,程序停止。

這些例外的目的是什麼?那麼,您可以編寫自己的代碼來捕獲特定類型的異常,並編寫自己的邏輯來處理異常情況。


2.捕捉異常:try-catch

Java 有一個異常捕獲機制,可以讓您停止這種異常終止的方法。它看起來像這樣:

try
{
   // Code where an exception might occur
}
catch(ExceptionType name)
{
   // Exception handling code
}

這種構造稱為try-catch塊。

可能發生異常的代碼用大括號括起來,前面有單詞try

在花括號之後,我們有關鍵字catch括號內是異常變量的聲明。其後是花括號,如果發生指定類型的異常,則將要執行的代碼包裹起來

如果在執行“ primary code ”的過程中沒有拋出異常,那麼catch塊裡面的代碼就不會被執行。如果發生異常,則為(如果拋出異常的類型與括號中變量的類型相同)。

例子:

代碼 控制台輸出
class Solution
{
   public static void main(String[] args)
   {
      System.out.println("Hadron Collider launched");

      try
      {
         launchHadronCollider(1);
         launchHadronCollider(0);
      }
      catch(Exception e)
      {
         System.out.println("Error! Caught an exception");
         System.out.println("The planet was sucked into a black hole!");
      }

      System.out.println("The Hadron Collider stopped");
   }

   public static void launchHadronCollider(int n)
   {
      System.out.println("Everything is working well: " + n);
      System.out.println(2/n);
      System.out.println("There are no problems: " + n);
   }
}
Hadron Collider launched
Everything is working fine: 1
2
There are no problems: 1
Everything is working fine: 0
Error! Caught an exception
The planet has been sucked into a black hole!
The Hadron Collider is stopped


3.多catch

多個 catch 塊

理論上,可以在一段代碼中拋出各種異常。有些你想用一種方式處理,有些你想用另一種方​​式處理,還有一些你會決定根本不處理。

Java 開發人員決定幫助您解決問題,讓您catch在一個塊之後編寫多個塊而不是一個塊try

try
{
   // Code where an exception might occur
}
catch (ExceptionType1 name1)
{
   // Code for handling ExceptionType1
}
catch (ExceptionType2 name2)
{
   // Code for handling ExceptionType2
}
   catch (ExceptionType3 name3)
{
   // Code for handling ExceptionType3
}

例子:

代碼 控制台輸出
class Solution
{
   public static void main(String[] args)
   {
      System.out.println("Start of main method");
      try
      {
         calculate(0);
      }
      catch (ArithmeticException e)
      {
         System.out.println("Division by 0");
      }
      catch(Exception e)
      {
         System.out.println("Caught some kind of exception");
      }

      System.out.println("End of main method");
   }

   public static void calculate(int n)
   {
      System.out.println("Start of calculate method: " + n);
      System.out.println(2/n);
      System.out.println("End of calculate method: " + n);
   }
}
Start of main method
Start of calculate method: 0
Division by 0
End of main method


catch4.塊的順序

塊中發生的異常try只能由單個塊捕獲catch。您不能有來自多個塊的代碼被執行的異常處理情況。catch

但是塊的順序很重要。

您可能會遇到異常可能被多個塊捕獲的情況。如果是這種情況,那麼異常將被最先出現的catch塊(最接近該try塊)捕獲。

怎麼會出現多個catch塊都能捕獲到同一個異常的情況呢?

所有異常都屬於一個單一的繼承層次結構——見圖表。

異常層次結構

ArithmeticException可以將一個對象分配給一個變量,該變量的類型是ArithmeticException或其任何祖先類: RuntimeException ,ExceptionThrowable— 參見圖表。

我們將在第 21 關詳細討論繼承和祖先類。

這段代碼將編譯得很好:

繼承的好處:
ArithmeticException ae    = new ArithmeticException();
RuntimeException runtime  = new ArithmeticException();
Exception exception       = new ArithmeticException();
Throwable trwbl           = new ArithmeticException();

ArithmeticException所以你可以用上面 4 個塊中的任何一個來捕獲 an catch

示例 1:

代碼 控制台輸出
class Solution
{
   public static void main(String[] args)
   {
      System.out.println("Start of main method");
      try
      {
         calculate(0);
      }
      catch(ArithmeticException e)
      {
         System.out.println("Division by 0");
      }
      catch(Exception e)
      {
         System.out.println("Caught some kind of exception");
      }

      System.out.println("End of main method");
   }

   public static void calculate(int n)
   {
      System.out.println("Start of calculate method: " + n);
      System.out.println(2/n);
      System.out.println("End of calculate method: " + n);
   }
}
Start of main method
Start of calculate method: 0
Division by 0
End of main method

在這個例子中, the可以被and塊ArithmeticException捕獲。它會被距離該區塊最近的區塊——第一個區塊——捕獲。catch (Exception e)catch (ArithmeticException e)trycatch

為避免意外,最好將catch幾乎可以捕獲所有異常的塊放在塊列表的末尾附近catch

Throwable類型通常能夠捕獲 Java 中的所有可能的異常。如果將它放在第一個catch塊中,則代碼將無法編譯,因為編譯器知道存在無法訪問的代碼塊。