Java異常處理實(shí)例教程
1、什么是異常?
首先,讓我們來(lái)看看下圖的例子:
在這個(gè)例子中,存在的錯(cuò)誤碼由除以0的結(jié)果。由于除以0而導(dǎo)致異常: ArithmeticException
HelloException.java
package com.yiibai.tutorial.exception;
public class HelloException {
public static void main(String[] args) {
System.out.println("Three");
// This division no problem.
int value = 10 / 2;
System.out.println("Two");
// This division no problem.
value = 10 / 1;
System.out.println("One");
// This division has problem, divided by 0.
// An error has occurred here.
value = 10 / 0;
// And the following code will not be executed.
System.out.println("Let's go!");
}
}
運(yùn)行這個(gè)例子,得到的結(jié)果是:

可以看到控制臺(tái)屏幕上的通知。錯(cuò)誤通知是很清楚的,包括代碼行的信息。
讓我們通過(guò)下圖中的流程看看下面的程序:
- 程序從(1),(2)至(5)步驟正常運(yùn)行。
- 在步驟(6)程序除以0。
- 程序跳轉(zhuǎn)出 main 方法后,而(7)代碼行還沒(méi)有被執(zhí)行。

我們將修改上述實(shí)施例的代碼。
HelloCatchException.java
package com.yiibai.tutorial.exception;
public class HelloCatchException {
public static void main(String[] args) {
System.out.println("Three");
// This division no problem.
int value = 10 / 2;
System.out.println("Two");
// This division no problem.
value = 10 / 1;
System.out.println("One");
try {
// This division has problem, divided by 0.
// An error has occurred here.
value = 10 / 0;
// And the following code will not be executed.
System.out.println("Value =" + value);
} catch (ArithmeticException e) {
// The code in the catch block will be executed
System.out.println("Error: " + e.getMessage());
// The code in the catch block will be executed
System.out.println("Ignore...");
}
// This code is executed
System.out.println("Let's go!");
}
}
運(yùn)行示例結(jié)果:
Three
Two
One
Error: / by zero
Ignore...
Let's go!
我們將按以下實(shí)例圖像的流程來(lái)解釋下面的程序。
- 步驟(1)至(5)是完全正常的。
- 異常發(fā)生在步驟(6),除以0出現(xiàn)了問(wèn)題。
- 它立即跳到catch塊執(zhí)行命令,步驟(7)被跳過(guò)。
- 步驟(8),(9)被執(zhí)行。
- 步驟(10)被執(zhí)行。

2、 異常層次結(jié)構(gòu)
這是Java異常的分層圖的模型。
最高的類(lèi)是:Throwable
兩個(gè)直接子類(lèi)是 Error 和 Exception。
在異常轉(zhuǎn)移有一個(gè)RuntimeException子類(lèi),包括Java中的編譯時(shí)未檢查異常。檢查并取消檢查在編譯時(shí),在下一部分的實(shí)施示例中說(shuō)明。
注意:您的類(lèi)應(yīng)該從兩個(gè)分支:Error或Exception繼承,而不是直接從Throwable繼承。

當(dāng)一個(gè)動(dòng)態(tài)鏈接失敗,或在虛擬機(jī)的一些其他的“硬”故障發(fā)生時(shí),虛擬機(jī)引發(fā)這個(gè)錯(cuò)誤。典型的Java程序不捕獲錯(cuò)誤,所以Java程序都不會(huì)拋出任何錯(cuò)誤。大多數(shù)程序拋出并捕獲從Exception類(lèi)派生的對(duì)象。異常指示出現(xiàn)了一個(gè)問(wèn)題,但是這些問(wèn)題并不是嚴(yán)重系統(tǒng)性問(wèn)題。你寫(xiě)的大多數(shù)程序?qū)?huì)拋出和捕獲異常。
Exception類(lèi)在Java包定義了許多子類(lèi)。這些子類(lèi)指明不同類(lèi)型的可能會(huì)發(fā)生異常。 例如,NegativeArraySizeException表明程序試圖創(chuàng)建一個(gè)大小為負(fù)的數(shù)組。
一個(gè)導(dǎo)演的子類(lèi)在Java語(yǔ)言中的特殊含義: RuntimeException類(lèi)表示Java虛擬機(jī)中發(fā)生(在運(yùn)行期間)的異常。運(yùn)行時(shí)異常的一個(gè)例子是NullYiibaierException異常,其中,當(dāng)一種方法試圖通過(guò)一個(gè)空引用來(lái)訪問(wèn)對(duì)象的成員時(shí)就會(huì)引發(fā)。 NullYiibaierException 可以在任何地方出現(xiàn)某個(gè)程序試圖取消引用一個(gè)對(duì)象的引用。經(jīng)常檢查異常捕獲的好處遠(yuǎn)遠(yuǎn)超過(guò)它的成本。
由于運(yùn)行時(shí)異常是無(wú)所不在的,在試圖捕獲或指定所有的時(shí)間是徒勞的作法(不可讀和不可維護(hù)的代碼), 編譯器允許運(yùn)行時(shí)異常去未捕獲和指定。
Java包定義幾個(gè)RuntimeException類(lèi)。您可以捕獲這些異常,就像其他異常。但是并不需要一種方法來(lái)指定它拋出運(yùn)行時(shí)異常。此外可以創(chuàng)建自己的RuntimeException子類(lèi)。 運(yùn)行時(shí)異常 - 下面討論包含何時(shí)以及如何使用運(yùn)行時(shí)異常進(jìn)行了深入探討。 3、使用try-catch處理異常
編寫(xiě)從Exception 繼承的類(lèi)。

AgeException.java
package com.yiibai.tutorial.exception.basic;
public class AgeException extends Exception {
public AgeException(String message) {
super(message);
}
}
TooYoungException.java
package com.yiibai.tutorial.exception.basic;
public class TooYoungException extends AgeException {
public TooYoungException(String message) {
super(message);
}
}
TooOldException.java
package com.yiibai.tutorial.exception.basic;
public class TooOldException extends AgeException {
public TooOldException(String message) {
super(message);
}
}
以及AgeUtils類(lèi)檢查年齡的檢查靜態(tài)方法。
AgeUtils.java
package com.yiibai.tutorial.exception.basic;
public class AgeUtils {
// This method checks the age.
// If age is less than 18, the method will throw an exception TooYoungException
// If age greater than 40, the method will throw an exception TooOldException
public static void checkAge(int age) throws TooYoungException,
TooOldException {
if (age < 18) {
// If age is less than 18, an exception will be thrown
// This method ends here.
throw new TooYoungException("Age " + age + " too young");
} else if (age > 40) {
// If age greater than 40, an exception will be thrown.
// This method ends here.
throw new TooOldException("Age " + age + " too old");
}
// If age is between 18-40.
// This code will be execute.
System.out.println("Age " + age + " OK!");
}
}
檢查異常和未經(jīng)檢查的異常:
AgeException是Exception,TooOldException的子類(lèi)和TooYoungException2是 AgeException直接子類(lèi),所以它們是“Checked Exception”
在AgeUtils.checkAge(int)方法已經(jīng)拋出異常,需要通過(guò)關(guān)鍵字“throws”,列出它們的方法聲明?;蛘呖梢月暶鲯伋龈嗟募?jí)別。
在使用 AgeUtils.checkAge(int) 位置也必須進(jìn)行處理,以捕獲異常,或繼續(xù)拋出去。

"Checked exception" 是由 "Java Compiler"來(lái)檢查。

有兩個(gè)選擇:

TryCatchDemo1.java
package com.yiibai.tutorial.exception.basic;
public class TryCatchDemo1 {
public static void main(String[] args) {
System.out.println("Start Recruiting ...");
// Check age
System.out.println("Check your Age");
int age = 50;
try {
AgeUtils.checkAge(age);
System.out.println("You pass!");
} catch (TooYoungException e) {
// Do something here ..
System.out.println("You are too young, not pass!");
System.out.println(e.getMessage());
} catch (TooOldException e) {
// Do something here ..
System.out.println("You are too old, not pass!");
System.out.println(e.getMessage());
}
}
}
在下面的例子中,我們將通過(guò)父類(lèi)捕獲異常(超Exception類(lèi))。
TryCatchDemo2.java
package com.yiibai.tutorial.exception.basic;
public class TryCatchDemo2 {
public static void main(String[] args) {
System.out.println("Start Recruiting ...");
// Check age
System.out.println("Check your Age");
int age = 15;
try {
// Here can throw TooOldException or TooYoungException
AgeUtils.checkAge(age);
System.out.println("You pass!");
} catch (AgeException e) {
// If an exception occurs, type of AgeException
// This catch block will be execute
System.out.println("Your age invalid, you not pass");
System.out.println(e.getMessage());
}
}
}
也可以組不同的異常在塊中來(lái)處理,如果它們對(duì)邏輯程序處理是相同的方式。
TryCatchDemo3.java
package com.yiibai.tutorial.exception.basic;
public class TryCatchDemo3 {
public static void main(String[] args) {
System.out.println("Start Recruiting ...");
// Check age
System.out.println("Check your Age");
int age = 15;
try {
// Here can throw TooOldException or TooYoungException
AgeUtils.checkAge(age);
System.out.println("You pass!");
} catch (TooYoungException | TooOldException e) {
// Catch multi exceptions in one block.
System.out.println("Your age invalid, you not pass");
System.out.println(e.getMessage());
}
}
}
4、 try-catch-finally
我們已習(xí)慣于通過(guò) try-catch 塊捕獲錯(cuò)誤。Try-catch-finally 來(lái)完全處理異常。
try {
// Do something here
} catch (Exception1 e) {
// Do something here
} catch (Exception2 e) {
// Do something here
} finally {
// Finally block is always executed
// Do something here
}
TryCatchFinallyDemo.java
package com.yiibai.tutorial.exception.basic;
public class TryCatchFinallyDemo {
public static void main(String[] args) {
String text = "001234A2";
int value = toInteger(text);
System.out.println("Value= " + value);
}
public static int toInteger(String text) {
try {
System.out.println("Begin parse text: " + text);
// An Exception can throw here (NumberFormatException).
int value = Integer.parseInt(text);
return value;
} catch (NumberFormatException e) {
// In the case of 'text' is not a number.
// This catch block will be executed.
System.out.println("Number format exception " + e.getMessage());
// Returns 0 if NumberFormatException occurs
return 0;
} finally {
System.out.println("End parse text: " + text);
}
}
}
這是程序的流程。 finally塊無(wú)論什么情況下總會(huì)被執(zhí)行。

5、 環(huán)繞異常
- 我們需要一些類(lèi)參與到這個(gè)例子:
- Person: 模擬一個(gè)受試者招募到公司的信息:姓名,年齡,性別。
- GenderException: 性別異常。
- ValidateException: 異常評(píng)估求職者。
- ValidateUtils: 靜態(tài)方法類(lèi)綜合評(píng)價(jià)面試者。
- 如果男性年齡在18-40之間的被認(rèn)為是有效的。
Person.java
package com.yiibai.tutorial.exception.wrap;
public class Person {
public static final String MALE = "male";
public static final String FEMALE = "female";
private String name;
private String gender;
private int age;
public Person(String name, String gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
GenderException.java
package com.yiibai.tutorial.exception.wrap;
// Gender Exception.
public class GenderException extends Exception {
public GenderException(String message) {
super(message);
}
}
ValidateException 類(lèi)包有其他異常。
ValidateException.java
package com.yiibai.tutorial.exception.wrap;
public class ValidateException extends Exception {
// Wrap an Exception
public ValidateException(Exception e) {
super(e);
}
}
ValidateUtils.java
package com.yiibai.tutorial.exception.wrap;
import com.yiibai.tutorial.exception.basic.AgeUtils;
public class ValidateUtils {
public static void checkPerson(Person person) throws ValidateException {
try {
// Check age.
// Valid if between 18-40
// This method can throw TooOldException, TooYoungException.
AgeUtils.checkAge(person.getAge());
} catch (Exception e) {
// If not valid
// Wrap this exception by ValidateException, and throw
throw new ValidateException(e);
}
// If that person is Female, ie invalid.
if (person.getGender().equals(Person.FEMALE)) {
GenderException e = new GenderException("Do not accept women");
throw new ValidateException(e);
}
}
}
WrapperExceptionDemo.java
package com.yiibai.tutorial.exception.wrap;
public class WrapperExceptionDemo {
public static void main(String[] args) {
// One participant recruitment.
Person person = new Person("Marry", Person.FEMALE, 20);
try {
// Exceptions may occur here.
ValidateUtils.checkPerson(person);
} catch (ValidateException wrap) {
// Get the real cause.
// May be TooYoungException, TooOldException, GenderException
Exception cause = (Exception) wrap.getCause();
if (cause != null) {
System.out.println("Not pass, cause: " + cause.getMessage());
} else {
System.out.println(wrap.getMessage());
}
}
}
}
6、RuntimeException和子類(lèi) RuntimeException類(lèi)及其子類(lèi)都是“未檢查的例外”。它不是由Java編譯器在編譯時(shí)進(jìn)行檢查。在某些情況下,你可以從這個(gè)分支繼承編寫(xiě)自己的異常。
下面是屬于RuntimeException分支一些類(lèi)(當(dāng)然,這還不是全部)。
一些處理這種類(lèi)型異常的例子:

6.1- NullYiibaierException
這是最常見(jiàn)的異常,通常會(huì)導(dǎo)致錯(cuò)誤在程序中。異常被拋出,當(dāng)你調(diào)用方法或訪問(wèn)一個(gè)空對(duì)象的字段。
NullYiibaierExceptionDemo.java
package com.yiibai.tutorial.exception.runtime;
public class NullYiibaierExceptionDemo {
// For example, here is a method that can return null string.
public static String getString() {
if (1 == 2) {
return "1==2 !!";
}
return null;
}
public static void main(String[] args) {
// This is an object that references not null.
String text1 = "Hello exception";
// Call the method retrieves the string length.
int length = text1.length();
System.out.println("Length text1 = " + length);
// This is an object that references null.
String text2 = getString();
// Call the method retrieves the string length.
// NullYiibaierException will occur here.
// It is an exception occurs at runtime (type of RuntimeException)
// Javac compiler does not force you to use a try-catch block to handle it
length = text2.length();
System.out.println("Finish!");
}
}
運(yùn)行示例的結(jié)果:

在現(xiàn)實(shí)中,像處理其他異常時(shí),可以使用 try-catch 來(lái)捕獲并處理這個(gè)異常。 然而,這是機(jī)械的,通常情況下,我們應(yīng)該檢查,以確保在使用它之前,對(duì)象不為空值。
您可以更正上面的代碼,使其類(lèi)似于下面的以避免空指針異常:
// This is a null object.
String text2 = getString();
// Check to make sure 'Text2' are not null.
// Instead of using try-catch.
if (text2 != null) {
length = text2.length();
}
6.2- ArrayIndexOfBoundException
當(dāng)您試圖訪問(wèn)一個(gè)無(wú)效的索引的數(shù)組元素就會(huì)發(fā)生此異常。例如,一個(gè)數(shù)組有10個(gè)元素可以訪問(wèn),但您訪問(wèn)的是索引為20的元素。
ArrayIndexOfBoundsExceptionDemo.java
package com.yiibai.tutorial.exception.runtime;
public class ArrayIndexOfBoundsExceptionDemo {
public static void main(String[] args) {
String[] strs = new String[] { "One", "Two", "Three" };
// Access to the element has index 0.
String str1 = strs[0];
System.out.println("String at 0 = " + str1);
// Access to the element has index 5.
// ArrayIndexOfBoundsException occur here.
String str2 = strs[5];
System.out.println("String at 5 = " + str2);
}
}
為了避免 ArrayIndexOfBoundsException,我們更多的應(yīng)該是檢查數(shù)組而不是使用try-catch。
if (strs.length > 5) {
String str2 = strs[5];
System.out.println("String at 5 = " + str2);
} else {
System.out.println("No elements with index 5");
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助。
相關(guān)文章
淺談springMVC中controller的幾種返回類(lèi)型
這篇文章主要介紹了淺談springMVC中controller的幾種返回類(lèi)型,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02
SpringBoot(cloud)自動(dòng)裝配bean找不到類(lèi)型的問(wèn)題
這篇文章主要介紹了SpringBoot(cloud)自動(dòng)裝配bean找不到類(lèi)型的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02
JAVA SE包裝類(lèi)和泛型詳細(xì)介紹及說(shuō)明方法
這篇文章主要介紹了JAVA SE包裝類(lèi)和泛型的相關(guān)資料,包括基本數(shù)據(jù)類(lèi)型與包裝類(lèi)的對(duì)應(yīng)關(guān)系,以及裝箱和拆箱的概念,并重點(diǎn)講解了自動(dòng)裝箱和自動(dòng)拆箱的機(jī)制,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-03-03
SSM框架實(shí)現(xiàn)分頁(yè)和搜索分頁(yè)的示例代碼
本篇文章主要介紹了SSM框架實(shí)現(xiàn)分頁(yè)和搜索分頁(yè)的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03
Spring中BeanUtils.copyProperties的坑及解決
這篇文章主要介紹了Spring中BeanUtils.copyProperties的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
Java字節(jié)與字符流永久存儲(chǔ)json數(shù)據(jù)
本篇文章給大家詳細(xì)講述了Java字節(jié)與字符流永久存儲(chǔ)json數(shù)據(jù)的方法,以及代碼分享,有興趣的參考學(xué)習(xí)下。2018-02-02

