一簡介
Java為我們提供了非常完美的異常處理機制使得我們可以更加專心的去寫程序有的時候遇到需要添加異常處理塊的地方像eclipse會自動提示你感覺很幸福!我們看看異常處理的一些類的結構組成
從根部開始分為兩大類Error和ExceptionError是程序無法處理的錯誤比如OutOfMemoryErrorThreadDeath等這些異常發生時Java虛擬機(JVM)一般會選擇線程終止Exception是程序本身可以處理的異常這種異常分兩大類非運行時異常(發生在編譯階段又稱checkException)和運行時異常(發生在程序運行過程中又叫uncheckException)非運行時異常一般就是指一些沒有遵守Java語言規范的代碼容易看的出來並且容易解決的異常運行時異常是那些在程序運行過程中產生的異常具有不確定性如空指針異常等造成空指針的原因很多所以運行時異常具有不確定性往往難以排查還有就是程序中存在的邏輯錯誤光從一段代碼中看不出問題需要縱觀全局才能發現的錯誤也會造成運行時異常這就要求我們在寫程序時多多注意盡量處理去處理異常當異常發生時希望程序能朝理想的方面運行!
二異常的類型
一方面我們可以將異常分為受控異常和不受控異常其實一般來講受控異常就是非運行時異常不受控異常就是運行時異常和Error另一方面我們直接將異常分為非運行時異常和運行時異常
三異常處理的過程
使用try/catch/finally語句塊安裝異常處理程序每個try塊中包含可能出現異常的語句每個catch塊中包含處理異常的程序
public class Test {
public static void main(String[] args) {
String filename = d:\\testtxt;
try {
FileReader reader = new FileReader(filename)
Scanner in = new Scanner(reader)
String input = innext()
int value = IntegerparseInt(input)
Systemoutprintln(value)
} catch (FileNotFoundException e) {
eprintStackTrace()
} finally {
Systemoutprintln(this is finally block!)
}
}
}
如果d盤根目錄下沒有testtxt的話該程序拋出異常
this is finally block!
javaioFileNotFoundException: d:\testtxt (系統找不到指定的文件)
at javaioFileInputStreamopen(Native Method)
at javaioFileInputStream<init>(FileInputStreamjava:)
at javaioFileInputStream<init>(FileInputStreamjava:)
at javaioFileReader<init>(FileReaderjava:)
at Testmain(Testjava:)
但是finally塊中的語句卻輸出了這個暫且不談先記著在d盤下新建文件testtxt並輸入內容再來觀察下
輸出
this is finally block!
finally塊中的語句依然輸出說明不論程序有無異常finally塊中的語句都會執行因此finally塊中一般放一些關閉資源的語句接下來我們繼續做實驗我們將testtxt中的改成abc看看結果
this is finally block!
Exception in thread main javalangNumberFormatException: For input string: abc
at javalangNumberFormatExceptionforInputString(NumberFormatExceptionjava:)
at javalangIntegerparseInt(Integerjava:)
at javalangIntegerparseInt(Integerjava:)
at Testmain(Testjava:)
該異常中的兩處重點我已經標出來了一處是紅色的Exception in thread main表明異常拋出的地方另一處是javalangNumberFormatException: For input string: abc表明異常的類型此處我們看看上面之前的那個結果為什麼沒有拋出異常出現的地方仔細觀察源程序我們發現程序中我們並沒有顯式聲明NumberFormatException而FileNotFoundException是我們聲明過的此處我總結一下就是說如果我在程序中聲明了某個異常則拋出異常的時候不會顯式出處直接拋出如果我沒有在程序中聲明那麼程序會同時拋出異常的出處這是為什麼?還有當我沒有顯式聲明的時候系統會怎麼辦?這肯定是有一定的規律的下面我們繼續做實驗
[java]
public class Test {
public static void main(String[] args) {
String filename = d:\\testtxt;
// 進行捕捉異常
try {
FileReader reader = new FileReader(filename)
Scanner in = new Scanner(reader)
String input = innext()
int value = IntegerparseInt(input)
Systemoutprintln(value)
} catch (FileNotFoundException e) { // 捕捉FileNotFoundException
eprintStackTrace()
} catch (NumberFormatException e) { // NumberFormatException
eprintStackTrace() // 打印異常信息 就是形如at javalangNumberFor…的信息
Systemoutprintln(Im here!)
} finally {
Systemoutprintln(this is finally block!)
}
}
}
我加了一個catch塊轉麼捕獲NumberFormatException則程序輸出
javalangNumberFormatException: For input string: abc
at javalangNumberFormatExceptionforInputString(NumberFormatExceptionjava:)
at javalangIntegerparseInt(Integerjava:)
at javalangIntegerparseInt(Integerjava:)
at Testmain(Testjava:)
Im here!
this is finally block!
沒有輸出異常拋出的地方繼續改代碼
[java]
public class Test {
public void open(){
String filename = d:\\testtxt;
try {
FileReader reader = new FileReader(filename)
Scanner in = new Scanner(reader)
String input = innext()
int value = IntegerparseInt(input)
Systemoutprintln(value)
} catch (FileNotFoundException e) {
eprintStackTrace()
Systemoutprintln(this is test block!)
}
}
}
[java]
public class Test {
public void carry() {
Test t = new Test()
try {
topen()
} catch (Exception e) {
eprintStackTrace()
Systemoutprintln(this is test block!)
}
}
}
[java]
public class Test {
public static void main(String[] args) {
Test t = new Test()
tcarry()
}
}
思路是Test類中處理業務Test類調用Test類的open方法最後在Test類中調用Test類的carry方法但是我將異常拋在Test中看看異常輸出的結果
javalangNumberFormatException: For input string: abc
at javalangNumberFormatExceptionforInputString(NumberFormatExceptionjava:)
at javalangIntegerparseInt(Integerjava:)
at javalangIntegerparseInt(Integerjava:)
at Testopen(Testjava:)
at Testcarry(Testjava:)
at Testmain(Testjava:)
this is test block!
首先拋出的異常沒有地方信息了其次輸出了this is test block!說明該異常是從Test類中的carry方法拋出的當我們把Test類中的異常捕獲語句注釋掉的時候異常如下
Exception in thread main javalangNumberFormatException: For input string: abc
at javalangNumberFormatExceptionforInputString(NumberFormatExceptionjava:)
at javalangIntegerparseInt(Integerjava:)
at javalangIntegerparseInt(Integerjava:)
at Testopen(Testjava:)
at Testcarry(Testjava:)
at Testmain(Testjava:)
看到此處我想讀者朋友們應該有一定的感覺了說了這麼多就是想說明一點當程序處理不了異常的時候會怎麼辦?是這樣的當前方法如果聲明了相應的異常處理器如上面的程序如果加了catch(NumberFormatException e)則直接拋出但是如果沒有聲明則會找到它的調用者如果調用者也沒有做相應的處理則會一直往前找直到找到main方法最後拋出異常所以上面的現象不難解釋!此處我們簡單總結下異常處理的過程在可能出錯的方法加上try/catch塊語句來調用異常處理器當異常發生時直接跳到相應的異常處理器catch中如果有則拋出異常執行該catch塊中的語句如果沒喲則找到它的調用者直到main方法如果有finally塊則執行finally塊中的語句
注意
一個try可對應多個catch有try必須至少有一個catchfinally塊不是必須的可有可無一般情況下當異常發生時會執行catch塊中的語句特殊情況當main方法中拋出異常時如果程序聲明了該異常處理器則執行相應的catch塊中的語句如果程序沒有聲明相應的異常處理器則不執行catch塊中的語句直接拋出異常!那麼這個異常來源於哪兒?既然main中有try/catch語句(雖然不是對應的異常處理器)為什麼沒有拋出說明main方法中的try/catch塊根本就沒有捕捉到異常那麼系統怎麼處理?其實是這樣的這種情況下異常被直接丟給JVM而JVM的處理方式就是直接中斷你的程序!就是這麼簡單
四常見異常
NullPointerException 空指針
空指針異常當應用試圖在要求使用對象的地方使用了null時拋出該異常譬如調用null對象的實例方法訪問null對象的屬性計算null對象的長度使用throw語句拋出null等等
ClassNotFoundException 找不到類
找不到類異常當應用試圖根據字符串形式的類名構造類而在遍歷CLASSPAH之後找不到對應名稱的class文件時拋出該異常
ClassCastException 類型轉換
ArithmeticException 算數條件
算術條件異常譬如整數除零等
ArrayIndexOutOfBoundsException 數組越界
數組索引越界異常當對數組的索引值為負數或大於等於數組大小時拋出
這塊內容我們會不斷更新請讀者朋友們在閱讀的同時不斷提出自己遇到的有意義的異常不斷充實博文歡迎讀者積極補充!
有任何問題請聯系egg
五異常和錯誤
異常 在Java中程序的錯誤主要是語法錯誤和語義錯誤一個程序在編譯和運行時出現的錯誤我們統一稱之為異常它是JVM(Java虛擬機)通知你的一種方式通過這種方式JVM讓你知道你已經犯了個錯誤現在有一個機會來修改它Java中使用異常類來表示異常不同的異常類代表了不同的異常但是在Java中所有的異常都有一個基類叫做Exception
錯誤它指的是一個合理的應用程序不能截獲的嚴重的問題大多數都是反常的情況錯誤是JVM的一個故障(雖然它可以是任何系統級的服務)所以錯誤是很難處理的一般的開發人員是無法處理這些錯誤的比如內存溢出
六Assert(斷言)
assert是jdk才開始支持的新功能主要在開發和測試時開啟為保證性能在程序正式發布後通常是關閉的啟用斷言比較簡單在啟動參數裡設置ea或者enableassertions就可以了
assert表達式有兩種情況
)assert exp 此時的exp為一個boolean類型的表達式
當其值為true時運行通過如果為false則會拋出一個相應的AssertionError注意它可以被catch到
)assert exp : exp 此時的exp同上而exp可以為基本類型或一個Object對象當exp的值為true時同上且exp不會被運算而當exp的值為false時將會拋出AssertionError同時將exp的結果作為AssertionError構造器中的參數當使用catch該錯誤時可利用getMessage()方法打印出exp的結果
使用斷言應該注意斷言只是用來調試程序的工具不要作為程序的一部分或者有人用斷言來代替try/catch這些都是不對的這和斷言的作用相違背斷言在程序發布後是會被關閉的如果將它作為程序的一部分那麼當斷言被關閉後程序必然會出問題有更好的方法如try/catch為什麼還用斷言所以最好不要講斷言作為程序的一部分從心裡上你可以把它當做可有可無就行了
七常見問題
finally和return問題
我們平時說finally中的內容不論程序有無異常都會被執行那麼如果我們的程序在try和catch塊中return了finally中的還會執行嗎?讀者可以先猜猜看分析一下接下來我們做實驗
[java]
public class FinallyTest {
public static void main(String[] args) {
boolean file = open()
Systemoutprintln(this is main return value: + file)
}
public static boolean open() {
String filename = d:\\testtxtp;
try {
FileReader reader = new FileReader(filename)
Scanner in = new Scanner(reader)
String input = innext()
int value = IntegerparseInt(input)
Systemoutprintln(value)
return true;
} catch (FileNotFoundException e) {
Systemoutprintln(this is catch_for_filenot… block!)
return false;
} finally {
Systemoutprintln(this is finally block!)
}
}
}
故意把filename寫錯造出異常輸出為下
this is catch_for_filenot… block!
this is finally block!
this is main return value:false
從這兒看出來程序先輸出catch塊中的後又去執行finally塊中的雖然在catch中已經返回了最後執行mian方法中的而且輸出false說明catch塊中的也成功返回了所以面對疑問我們可以很肯定的回答即使有return語句finally塊也一定會被執行!
盡量不要將catch和finally一起使用
像我上面演示程序那樣try/catch/finally一起使用在《Big Java》一書中提到不建議這樣做因為會影響程序的可讀性最好的做法是用try/catch嵌套catch用來捕獲異常finally用來關閉資源修改如下
[java]
public class FinallyTest {
public static void main(String[] args) {
boolean file = open()
Systemoutprintln(this is main return value: + file)
}
public static boolean open() {
String filename = d:\\testtxtp;
try {
try {
FileReader reader = new FileReader(filename)
Scanner in = new Scanner(reader)
String input = innext()
int value = IntegerparseInt(input)
Systemoutprintln(value)
return true;
} finally {
// 一些關閉資源的操作
Systemoutprintln(this is finally block!)
}
} catch (FileNotFoundException e) {
Systemoutprintln(this is catch_for_filenot… block!)
return false;
}
}
}
自定義異常
畢竟系統自帶的異常處理器並不能滿足所有需求因為對於我們開發人員來說拋出的異常越細致我們越容易找到問題總不能所有的問題都拋出Exception吧?太籠統了在實際的開發中我們可以根據自己的需要進行自定義異常處理器
[java]
/**
* 自定義異常處理器繼承Exception或者RuntimeException依情況而定
* @author erqing
*
*/
public class NameNotSupportException extends RuntimeException {
private static final long serialVersionUID = L;
public NameNotSupportException() {
}
public NameNotSupportException(String message) {
super(message)
}
}
[java]
public class DefineTest {
public static void main(String[] args) {
String name = egg;
if(!erqingequals(name)){
throw new NameNotSupportException(erqing)
}else{
Systemoutprintln(name is OK!)
}
}
}
[java]
Exception in thread main NameNotSupportException: erqing
at DefineTestmain(DefineTestjava:)
From:http://tw.wingwit.com/Article/program/Java/hx/201311/25806.html