1.異常類型
所有的異常分為4種類型,它們實際上是相互繼承的類。
Throwable
班級
所有異常的基類是類Throwable
。該類Throwable
包含將當前調用堆棧(當前方法的堆棧跟踪)寫入數組的代碼。稍後我們將了解堆棧跟踪是什麼。
throw運算符只能接受從Throwable
類派生的對象。儘管理論上您可以編寫類似 的代碼throw new Throwable();
,但通常沒有人這樣做。該類的主要目的Throwable
是為所有異常提供一個父類。
Error
班級
下一個異常類是Error
類,直接繼承Throwable
類。當出現嚴重問題時, Java 機器會創建該類Error
(及其後代)的對象。例如,硬件故障、內存不足等。
通常,作為程序員,在程序中出現這樣的錯誤(應該拋出an 的那種)時,您無能為力:這些錯誤太嚴重了。Error
您所能做的就是通知用戶程序正在崩潰和/或將有關錯誤的所有已知信息寫入程序日誌。
Exception
班級
和Exception
類RuntimeException
是針對很多方法運行中出現的常見錯誤。每個拋出的異常的目標是被知道如何正確處理它的塊捕獲。catch
當一個方法由於某種原因不能完成它的工作時,它應該立即通過拋出適當類型的異常來通知調用方法。
換句話說,如果一個變量等於null
,該方法將拋出一個NullPointerException
。如果將不正確的參數傳遞給該方法,它將拋出一個InvalidArgumentException
. 如果該方法不小心被零除,它會拋出一個ArithmeticException
.
RuntimeException
班級
RuntimeExceptions
是 的一個子集Exceptions
。我們甚至可以說這RuntimeException
是普通異常 ( ) 的輕量級版本Exception
——對此類異常施加的要求和限制更少
Exception
稍後您將了解 和 之間的區別RuntimeException
。
2. Throws
:檢查異常
所有 Java 異常都分為兩類:已檢查和未檢查。
所有繼承RuntimeException
or的異常Error
都被認為是未經檢查的異常。 所有其他都是已檢查的異常。
在引入檢查異常 20 年後,幾乎每個 Java 程序員都認為這是一個錯誤。在流行的現代框架中,95% 的異常都是未經檢查的。幾乎一模一樣照抄Java的C#語言,並沒有加入checked exceptions。
已檢查異常和未檢查異常之間的主要區別是什麼?
對已檢查的異常有額外的要求。粗略地說,它們是這些:
要求 1
如果一個方法拋出一個已檢查的異常,它必須在它的簽名中指明異常的類型。這樣,調用它的每個方法都知道這個“有意義的異常”可能會發生在其中。
在關鍵字後的方法參數後面指明檢查異常(不要誤用關鍵字)。它看起來像這樣:throws
throw
type method (parameters) throws exception
例子:
檢查異常 | 未經檢查的異常 |
---|---|
|
|
在右邊的例子中,我們的代碼拋出了一個未經檢查的異常——不需要額外的操作。 在左側的示例中,該方法拋出一個已檢查的異常,因此throws
將關鍵字與異常類型一起添加到方法簽名中。
如果一個方法希望拋出多個已檢查的異常,則必須在關鍵字後指定所有這些異常throws
,並以逗號分隔。順序並不重要。例子:
public void calculate(int n) throws Exception, IOException
{
if (n == 0)
throw new Exception("n is null!");
if (n == 1)
throw new IOException("n is 1");
}
要求 2
如果您調用的方法在其簽名中包含已檢查的異常,則您不能忽略它拋出異常的事實。
您必須通過catch
為每個異常添加塊來捕獲所有此類異常,或者將它們添加到您的方法的throws
子句中。
就好像我們在說,“這些異常非常重要,我們必須捕獲它們。如果我們不知道如何處理它們,那麼必須通知任何可能調用我們方法的人,其中可能會發生此類異常。
例子:
想像一下,我們正在編寫一種方法來創建一個由人類居住的世界。初始人數作為參數傳遞。所以如果人數太少,我們需要添加例外。
創造地球 | 筆記 |
---|---|
|
該方法可能會拋出兩個已檢查的異常:
|
此方法調用可以通過 3 種方式處理:
1.不要捕獲任何異常
當方法不知道如何正確處理這種情況時,通常會這樣做。
代碼 | 筆記 |
---|---|
|
調用方法不捕獲異常並且必須將它們通知其他人:它將它們添加到自己的throws 子句中 |
2.捕捉一些異常
我們處理我們可以處理的錯誤。但是我們不理解的,我們把它們丟給調用方法。為此,我們需要將他們的名字添加到 throws 子句中:
代碼 | 筆記 |
---|---|
|
調用者只捕獲一個已檢查的異常—— LonelyWorldException . 另一個異常必須添加到它的簽名中,在throws 關鍵字之後表明它 |
3.捕獲所有異常
如果該方法沒有向調用方法拋出異常,那麼調用方法總是確信一切正常。並且它將無法採取任何行動來修復異常情況。
代碼 | 筆記 |
---|---|
|
所有異常都在此方法中捕獲。來電者將確信一切順利。 |
3.捕獲多個異常
程序員真的很討厭重複代碼。他們甚至提出了相應的開發原則——DRY : Don't Repeat Yourself。但是在處理異常時,經常會try
出現一個塊後面跟著幾個catch
具有相同代碼的塊的情況。
或者可能有 3 個catch
塊具有相同的代碼,另外 2 個catch
塊具有其他相同的代碼。當您的項目負責任地處理異常時,這是一種標準情況。
從版本 7 開始,在 Java 語言中添加了在單個塊中指定多種異常類型的功能catch
。它看起來大致是這樣的:
try
{
// Code where an exception might occur
}
catch (ExceptionType1 | ExceptionType2 | ExceptionType3 name)
{
// Exception handling code
}
您可以擁有catch
任意數量的塊。但是,單個catch
塊不能指定相互繼承的異常。也就是說不能寫catch( Exception
| RuntimeException
e),因為RuntimeException
類繼承了Exception
。
GO TO FULL VERSION