1. 介紹
當你開始使用 Java 程式設計時,勢必會遇到「例外處理」這個詞彙。在各種關鍵字中,throw 與 throws 對初學者尤其令人困惑,因為它們看起來相似卻有不同的用途。
Java 是一門以安全性與韌性為設計目標的語言,提供了內建機制來妥善處理錯誤與意外情況。這個機制稱為「例外處理」。例外處理在提升程式的可靠性與可維護性方面扮演關鍵角色。
本文將聚焦於「java throws」的使用方式,從例外處理的基礎說起,接著探討常見問答與常見陷阱。此指南特別適合對 throw 與 throws 差異仍感到不確定,或想了解何時、如何有效使用 throws 的讀者。我們也會提供實務資訊、技巧與在真實專案中常見的範例程式碼,請務必閱讀至最後。
2. 什麼是 Java 的例外處理?
在撰寫 Java 程式時,執行期間可能會出現各種意外情況。例如,找不到檔案、除以零錯誤,或嘗試存取陣列超出範圍的索引。這些情況稱為「例外」。
2.1 例外處理的基本概念
例外處理是一種機制,能偵測程式執行過程中發生的異常情況(例外),並讓開發者適當地處理它們。與其在例外發生時直接終止程式,Java 允許應用程式根據錯誤的類型與內容作出有意義的回應,從而提升應用的穩定性與使用者體驗。
2.2 已檢查例外與未檢查例外
Java 的例外分為兩大類。
已檢查例外(Checked Exceptions)
已檢查例外是必須在編譯期處理的例外。例如在檔案操作時可能拋出的 IOException。這類例外必須以 try‑catch 區塊捕捉,或透過 throws 宣告向呼叫端傳遞。
try {
FileReader fr = new FileReader("data.txt");
} catch (IOException e) {
e.printStackTrace();
}
未檢查例外(Unchecked Exceptions)
未檢查例外是不需要在編譯期強制處理的例外。常見的例子有 NullPointerException 與 ArrayIndexOutOfBoundsException,通常是程式設計錯誤所致。雖然 Java 在未明確處理這類例外時仍能編譯通過,但建議在必要時加以處理,以免發生意外錯誤。
2.3 為什麼需要例外處理
妥善實作例外處理可帶來以下好處:
- 提升程式穩定性: 即使發生意外錯誤,程式仍能顯示適當訊息或執行復原邏輯,而不會直接崩潰。
- 更易除錯: 例外的類型與訊息有助於快速定位問題根源。
- 改善使用者體驗: 系統不會因錯誤而突然終止,而是提供有意義的回饋或復原步驟。
例外處理是建構韌性應用程式的必備技能。接下來的章節,我們將說明 throw 的基礎用法。
3. 什麼是 throw?
在 Java 中,throw 是用來主動產生例外的關鍵字。雖然例外常會在程式執行時自動發生,但當特定條件成立時,你可能需要自行建立並拋出例外——這時就會使用 throw。
3.1 throw 的基本用法
throw 會明確產生一個例外物件並拋出,使例外發生。其基本語法如下:
throw new ExceptionClass("Error message");
例如,當傳入無效參數時,你可以這樣拋出例外:
public void setAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("Age must be zero or greater");
}
this.age = age;
}
在這個範例中,當年齡小於零時,會擲出 IllegalArgumentException。
3.2 為什麼你可能想要擲出例外
使用 “throw” 的主要目的是立即通知程式無效狀態或規則違反。這有助於及早捕捉錯誤並防止未預期的行為。 範例包括:
- 使用者輸入驗證失敗時
- 傳入無效參數或設定時
- 業務邏輯防止進一步處理時
3.3 使用 throw 的注意事項
當使用 “throw” 擲出例外時,除非在同一方法中使用 try-catch 區塊處理,否則它會傳播到呼叫者。對於 checked exceptions(例如 IOException),方法必須在其簽章中宣告 “throws”。對於 unchecked exceptions,throws 宣告是選項的,但了解 “throw” 和 “throws” 之間的差異對於正確使用至關重要。
4. throws 是什麼?
在撰寫 Java 程式時,你可能會在方法宣告中遇到 “throws” 關鍵字。throws 關鍵字用來通知呼叫者,該方法在執行期間可能擲出一個或多個例外。
4.1 throws 的基本用法
透過在方法宣告中指定例外類別名稱,throws 關鍵字將方法內可能發生的任何例外傳播到其呼叫者。特別是 checked exceptions,必須使用 throws 宣告以確保呼叫者正確處理它們。 範例:
public void readFile(String path) throws IOException {
FileReader reader = new FileReader(path);
// File reading process
}
在這個範例中,FileReader 的建構子可能擲出 IOException,因此方法必須宣告 throws IOException。
4.2 方法宣告中的例外傳播
當方法宣告 throws 時,其內發生的任何例外都會傳播到呼叫者。呼叫者然後必須捕捉例外或透過宣告自己的 throws 進一步傳播它。
public void processFile() throws IOException {
readFile("test.txt"); // readFile throws IOException, so this method must also declare throws
}
4.3 宣告多個例外
如果方法可能擲出多個例外,它們可以使用逗號分隔的清單在 throws 關鍵字後宣告。
public void connect(String host) throws IOException, SQLException {
// Network or database operations
}
4.4 throws 的角色與益處
- 改善可讀性與可維護性: throws 宣告讓人立即清楚方法可能擲出何種例外,提升開發者之間的溝通。
- 明確的錯誤處理責任: throws 確保呼叫者必須處理例外,促進穩健且結構化的系統設計。
- 支援自訂例外: 開發者可以在 throws 宣告中包含自訂例外類別,以更有效地處理複雜的錯誤情境。
5. throw 和 throws 的差異
雖然經常混淆,“throw” 和 “throws” 在 Java 的例外處理機制中擁有非常不同的角色。本章澄清它們的差異並解釋何時以及如何正確使用每個。
5.1 throw 和 throws 的功能差異
| Item | throw | throws |
|---|---|---|
| Role | Actually generates an exception | Declares that a method may throw exceptions |
| Usage | Used inside methods to throw exception objects | Used in method declarations to specify throwable exceptions |
| Target | Exception objects created with new | Both checked and unchecked exceptions |
| Example | throw new IOException(“Error occurred”); | public void sample() throws IOException |
| When required | When intentionally raising an exception | When a method may throw checked exceptions |
5.2 每個的使用情境
- throw
- 當你想要主動產生例外時使用—例如,偵測到無效輸入或規則違反時。
- 範例:「如果年齡小於零,擲出 IllegalArgumentException。」
- throws
- 當方法或建構子可能擲出例外並必須告知呼叫者時使用。
- 範例:「在處理檔案操作或資料庫存取的方法中使用 throws,其中預期會有例外。」

5.3 比較的程式碼範例
throw 的範例:
public void setName(String name) {
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("Name cannot be empty");
}
this.name = name;
}
throws 範例:
public void loadConfig(String path) throws IOException {
FileReader reader = new FileReader(path);
// Configuration loading process
}
5.4 摘要表格
| Decision Point | throw | throws |
|---|---|---|
| Where it’s used | Inside a method | Method declaration |
| What it does | Generates an exception | Declares exception propagation |
| Who handles it | Thrown at the point of error | Handled by the caller |
| When required | Optional (only when needed) | Required for checked exceptions |
throw 與 throws 的角色顯然不同,因此了解 在何種情境下使用哪一個 是實作健全例外處理的第一步。
6. 使用 throws 的最佳實踐
有效使用 throws 能提升 Java 程式的可讀性與可維護性,同時增進例外處理的整體品質。本章將介紹在實務開發中常見的建議做法與重要考量。
6.1 指定具體的例外類別
在 throws 宣告中,應盡可能指定最具體的例外類別。
避免廣泛宣告 Exception 或 Throwable。
透過使用像 IOException 或 SQLException 這樣的具體例外,呼叫端能精確判斷如何處理錯誤。
良好範例:
public void saveData() throws IOException {
// File-saving process
}
避免這樣寫:
public void saveData() throws Exception {
// Too vague: unclear what exceptions may occur
}
6.2 善用例外層級結構
由於 Java 的例外類別形成層級結構,相關的例外可在適當時候歸入同一父類別。
然而,避免使用過於高層的例外(例如 Exception)過度概括,因為這會降低清晰度,使錯誤處理變得更困難。

6.3 在 Javadoc 中使用 @throws 標籤
在提供 API 或函式庫時,應於 Javadoc 註解中使用 @throws 標籤說明例外。
此方式能清楚說明例外發生的條件,協助 API 使用者正確實作例外處理。
/**
* Reads a file.
* @param filePath Path of the file to read
* @throws IOException If the file cannot be read
*/
public void readFile(String filePath) throws IOException {
// ...
}
6.4 避免不必要的例外重新拋出
避免僅捕獲例外後再重新拋出而未提供任何價值。
若確實需要重新拋出,請將原始例外包裝於自訂例外中,或加入額外的上下文或日誌資訊。
6.5 使用自訂例外類別
在企業應用與大型系統中,常會自訂例外類別並於 throws 宣告中使用。
此作法有助於釐清錯誤原因與責任,使系統更易於維護與擴充。
public class DataNotFoundException extends Exception {
public DataNotFoundException(String message) {
super(message);
}
}
public void findData() throws DataNotFoundException {
// Throw when data is not found
}
適當使用 throws 可分散例外處理的責任、簡化除錯,並打造可靠且安全的 Java 應用程式。
7. 實務例外處理模式
Java 的例外處理不僅僅是簡單的 try-catch 區塊或 throws 宣告。
本章將介紹在實務開發中常見的實用模式與設計策略。
7.1 使用 try-with-resources 進行資源管理
在處理檔案、網路連線或資料庫連線時,即使發生例外,也必須正確釋放資源。
自 Java 7 起,try-with-resources 陳述式可自動關閉資源。
try (FileReader reader = new FileReader("data.txt")) {
// File reading process
} catch (IOException e) {
System.out.println("Failed to read file: " + e.getMessage());
}
此語法可確保自動呼叫 close(),即使發生例外也能防止資源洩漏。
7.2 高效處理多重例外
複雜的操作可能會產生多種例外類型。自 Java 7 起,您可以使用 multi‑catch 功能在單一 catch 子句中捕獲多個例外。
try {
methodA();
methodB();
} catch (IOException | SQLException e) {
// Handle both exceptions here
e.printStackTrace();
}
您也可以分開 catch 區塊,為每種例外類型提供自訂的處理方式。
7.3 例外處理的效能考量
雖然例外功能強大,但不應取代一般的控制流程。產生例外需要相當的開銷,因為必須建立堆疊追蹤 (stack trace),因此應僅保留給真正的例外情況。錯誤的使用方式(不建議):
try {
int value = array[index];
} catch (ArrayIndexOutOfBoundsException e) {
// Bounds checking should be done beforehand
}
建議的使用方式:
if (index >= 0 && index < array.length) {
int value = array[index];
} else {
// Out-of-range handling
}
7.4 日誌與通知
適當的日誌記錄與警示對於例外發生時的故障排除至關重要。企業系統常使用日誌框架(例如 Log4j、SLF4J)來記錄詳細的例外資訊。
catch (Exception e) {
logger.error("An error has occurred", e);
}
7.5 實作自訂復原邏輯
在某些情況下,實作復原邏輯(例如重試操作、重新載入設定檔或通知使用者)是有幫助的。與其立即終止程式,不如盡可能維持服務的連續性。透過採用實用的例外處理技巧,您可以打造既可靠又易於維護的 Java 應用程式。
8. 常見問題 (FAQ)
以下列出初學者在 Java 例外處理(尤其是與 “throws” 相關)時常見的問題與解答。
Q1. throw 與 throws 之主要差異為何?
A1.
throw 是一個關鍵字,用於在程式執行時實際產生例外。
throws 用於方法宣告中,宣告可能拋出例外。
→ 記憶此差異的好方法:throw = 「執行」,throws = 「宣告」。
Q2. 使用 throws 時需要注意什麼?
A2.
使用 throws 宣告的例外必須由呼叫端捕獲,或再以 throws 方式向上拋出。對於已檢查例外(checked exception),必須明確處理。若未捕獲或拋出例外,程式將無法編譯。
Q3. 可以同時使用 throw 與 throws 嗎?
A3.
可以。
常見的做法是在方法內使用 throw 拋出例外,同時在方法宣告中使用 throws 宣告相同的例外,讓例外傳遞給呼叫端。
Q4. 如何在 throws 中宣告多個例外?
A4.
在 throws 關鍵字之後以逗號分隔列出多個例外。
範例:public void sample() throws IOException, SQLException
Q5. 應該在 unchecked 例外上使用 throws 嗎?
A5.
未檢查例外(繼承自 RuntimeException)不需要使用 throws 來宣告。然而,若您希望明確告知呼叫端方法可能拋出特定的未檢查例外,仍可使用 throws,以提升可讀性與 API 的清晰度。
Q6. 在 throws 子句中宣告 Exception 或 Throwable 可以嗎?
A6.
技術上可以,但不建議這麼做。宣告過於寬泛的例外類型(如 Exception 或 Throwable)會讓人不清楚可能發生哪種錯誤,且使呼叫端難以正確處理。盡可能使用具體的例外類別。
Q7. 是否必須捕獲在 throws 中宣告的例外?
A7.
對於已檢查例外(checked exception),呼叫端必須捕捉該例外或使用 throws 進一步向上拋出。
未這樣做會導致編譯錯誤。
未檢查例外(unchecked exception)則不需要這兩者。
Q8. 如果我忘記寫 throws 會發生什麼事?
A8.
如果方法拋出已檢查例外卻未在宣告中使用 throws,編譯時會產生錯誤。
對於未檢查例外,即使沒有 throws,方法仍能正常編譯,但仍應實作適當的錯誤處理。
使用此 FAQ 章節可加深您對 Java 例外處理的了解。

