❶ 異常處理機制-Exception
一 簡介
java為我們提供了非常完美的異常處理機制 使得我們可以更加專心的去寫程序 有的時候遇到需要添加異常處理塊的地方 像eclipse會自動提示你 感覺很幸福!我們看看異常處理的一些類的結構組成
從根部開始分為兩大類 Error和Exception Error是程序無法處理的錯誤 比如OutOfMemoryError ThreadDeath等 這些異常發生時 Java虛擬機(JVM)一般會選擇線程終止 Exception是程序本身可以處理的異常 這種異常分兩大類 非運行時異常(發生在編譯階段 又稱checkException)和運行時異常(發生在程序運行過程中 又叫uncheckException) 非運行時異常一般就是指一些沒有遵守Java語言規范的代碼 容易看的出來 並且容易解決的異常 運行時異常是那些在程序運行過程中產生的異常 具有不確定性 如空指針異常等 造成空指針的原因很多 所以運行時異常具有不確定性 往往難以排查 還有就是程序中存在的邏輯錯誤 光從一段代碼中看不出問題 需要縱觀全局才能發現的錯誤 也會造成運行時異常 這就要求我們在寫程序時多多注意 盡量處理去處理異常 當異常發生時 希望程序能朝理想的方面運行!
二 異常的類型
一方面我們可以將異常分為受控異常和不受控異常 其實一般來講 受控異常就是非運行時異常 不受控異常就是運行時異常和Error 另一方面 我們直接將異常分為非運行時異常和運行時異常
三 異常處理的過程
使用try/catch/finally語句塊安裝異常處理程序 每個try塊中包含可能出現異常的語句 每個catch塊中包含處理異常的程序
public class Test {
public static void main(String[] args) {
String filename = d:\test txt ;
try {
FileReader reader = new FileReader(filename)
Scanner in = new Scanner(reader)
String input = in next()
int value = Integer parseInt(input)
System out println(value)
} catch (FileNotFoundException e) {
e printStackTrace()
} finally {
System out println( this is finally block! )
}
}
}
如果d盤根目錄下沒有test txt的話 該程序拋出異常
this is finally block!
java io FileNotFoundException: d: est txt (系統找不到指定的文件 )
at java io FileInputStream open(Native Method)
at java io FileInputStream <init>(FileInputStream java: )
at java io FileInputStream <init>(FileInputStream java: )
at java io FileReader <init>(FileReader java: )
at Test main(Test java: )
但是finally塊中的語句卻輸出了 這個暫且不談 先記著 在d盤下新建文件test txt 並輸入內容 再來觀察下
輸出
this is finally block!
finally塊中的語句依然輸出 說明 不論程序有無異常 finally塊中的語句都會執行 因此finally塊中一般放一些關閉資源的語句 接下來我們繼續做實驗 我們將test txt中的 改成abc 看看結果
this is finally block!
Exception in thread main java lang NumberFormatException: For input string: abc
at java lang NumberFormatException forInputString(NumberFormatException java: )
at java lang Integer parseInt(Integer java: )
at java lang Integer parseInt(Integer java: )
at Test main(Test java: )
該異常中的兩處重點我已經標出來了 一處是紅色的Exception in thread main 表明異常拋出的地方 另一處是java lang NumberFormatException: For input string: abc 表明異常的類型 此處我們看看上面之前的那個結果 為什麼沒有拋出異常出現的地方 仔細觀察源程序 我們發現 程序中我們並沒有顯式聲明NumberFormatException 而FileNotFoundException是我們聲明過的 此處我總結一下就是說 如果我在程序中聲明了某個異常 則拋出異常的時候 不會顯式出處 直接拋出 如果我沒有在程序中聲明 那麼程序會同時拋出異常的出處 這是為什麼?還有 當我沒有顯式聲明的時候 系統會怎麼辦?這肯定是有一定的規律的 下面我們繼續做實驗
[java]
public class Test {
public static void main(String[] args) {
String filename = d:\test txt ;
// 進行捕捉異常
try {
FileReader reader = new FileReader(filename)
Scanner in = new Scanner(reader)
String input = in next()
int value = Integer parseInt(input)
System out println(value)
} catch (FileNotFoundException e) { // 捕捉FileNotFoundException
e printStackTrace()
} catch (NumberFormatException e) { // NumberFormatException
e printStackTrace() // 列印異常信息 就是形如 at java lang NumberFor…的信息
System out println( I m here! )
} finally {
System out println( this is finally block! )
}
}
}
我加了一個catch塊 轉么捕獲NumberFormatException 則程序輸出
java lang NumberFormatException: For input string: abc
at java lang NumberFormatException forInputString(NumberFormatException java: )
at java lang Integer parseInt(Integer java: )
at java lang Integer parseInt(Integer java: )
at Test main(Test java: )
I m here!
this is finally block!
沒有輸出異常拋出的地方 繼續改代碼
[java]
public class Test {
public void open(){
String filename = d:\test txt ;
try {
FileReader reader = new FileReader(filename)
Scanner in = new Scanner(reader)
String input = in next()
int value = Integer parseInt(input)
System out println(value)
} catch (FileNotFoundException e) {
e printStackTrace()
System out println( this is test block! )
}
}
}
[java]
public class Test {
public void carry() {
Test t = new Test ()
try {
t open()
} catch (Exception e) {
e printStackTrace()
System out println( this is test block! )
}
}
}
[java]
public class Test {
public static void main(String[] args) {
Test t = new Test ()
t carry()
}
}
思路是 Test 類中處理業務 Test 類調用Test 類的open方法 最後在Test類中調用Test 類的carry方法 但是 我將異常拋在Test 中 看看異常輸出的結果
java lang NumberFormatException: For input string: abc
at java lang NumberFormatException forInputString(NumberFormatException java: )
at java lang Integer parseInt(Integer java: )
at java lang Integer parseInt(Integer java: )
at Test open(Test java: )
at Test carry(Test java: )
at Test main(Test java: )
this is test block!
首先 拋出的異常沒有地方信息了 其次輸出了 this is test block! 說明該異常是從Test 類中的carry方法拋出的 當我們把Test 類中的異常捕獲語句注釋掉的時候 異常如下
Exception in thread main java lang NumberFormatException: For input string: abc
at java lang NumberFormatException forInputString(NumberFormatException java: )
at java lang Integer parseInt(Integer java: )
at java lang Integer parseInt(Integer java: )
at Test open(Test java: )
at Test carry(Test java: )
at Test main(Test java: )
看到此處 我想讀者朋友們應該有一定的感覺了 說了這么多 就是想說明一點 當程序處理不了異常的時候會怎麼辦?是這樣的 當前方法如果聲明了相應的異常處理器 如上面的程序如果加了catch(NumberFormatException e) 則直接拋出 但是如果沒有聲明 則會找到它的調用者 如果調用者也沒有做相應的處理 則會一直往前找 直到找到main方法 最後拋出異常 所以上面的現象不難解釋!此處我們簡單總結下異常處理的過程 在可能出錯的方法加上try/catch塊語句 來調用異常處理器 當異常發生時 直接跳到相應的異常處理器catch中 如果有則拋出異常 執行該catch塊中的語句 如果沒喲 則找到它的調用者 直到main方法 如果有finally塊 則執行finally塊中的語句
注意
一個try可對應多個catch 有try必須至少有一個catch finally塊不是必須的 可有可無 一般情況下 當異常發生時 會執行catch塊中的語句 特殊情況 當main方法中拋出異常時 如果程序聲明了該異常處理器 則執行相應的catch塊中的語句 如果程序沒有聲明相應的異常處理器 則不執行catch塊中的語句 直接拋出異常!那麼 這個異常來源於哪兒?既然main中有try/catch語句(雖然不是對應的異常處理器) 為什麼沒有拋出 說明main方法中的try/catch塊根本就沒有捕捉到異常 那麼系統怎麼處理?其實是這樣的 這種情況下 異常被直接丟給JVM 而JVM的處理方式就是 直接中斷你的程序!就是這么簡單
四 常見異常
NullPointerException 空指針
空指針異常 當應用試圖在要求使用對象的地方使用了null時 拋出該異常 譬如 調用null對象的實例方法 訪問null對象的屬性 計算null對象的長度 使用throw語句拋出null等等
ClassNotFoundException 找不到類
找不到類異常 當應用試圖根據字元串形式的類名構造類 而在遍歷CLASSPAH之後找不到對應名稱的class文件時 拋出該異常
ClassCastException 類型轉換
ArithmeticException 算數條件
算術條件異常 譬如 整數除零等
數組越界
數組索引越界異常 當對數組的索引值為負數或大於等於數組大小時拋出
這塊內容我們會不斷更新 請讀者朋友們在閱讀的同時 不斷提出自己遇到的有意義的異常 不斷充實博文 歡迎讀者積極補充!
有任何問題 請聯系 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()
System out println( this is main return value: + file)
}
public static boolean open() {
String filename = d:\test txtp ;
try {
FileReader reader = new FileReader(filename)
Scanner in = new Scanner(reader)
String input = in next()
int value = Integer parseInt(input)
System out println(value)
return true;
} catch (FileNotFoundException e) {
System out println( this is catch_for_filenot… block! )
return false;
} finally {
System out println( 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()
System out println( this is main return value: + file)
}
public static boolean open() {
String filename = d:\test txtp ;
try {
try {
FileReader reader = new FileReader(filename)
Scanner in = new Scanner(reader)
String input = in next()
int value = Integer parseInt(input)
System out println(value)
return true;
} finally {
// 一些關閉資源的操作
System out println( this is finally block! )
}
} catch (FileNotFoundException e) {
System out println( 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(! erqing equals(name)){
throw new NameNotSupportException( erqing )
}else{
System out println( name is OK! )
}
}
}
[java]
Exception in thread main NameNotSupportException: erqing
lishixin/Article/program/Java/hx/201311/25806
❷ Java代碼如何優化從哪些方面入手分析
1)盡量指定類、方法的final修飾符。帶有final修飾符的類是不可派生的,Java編譯器會尋找機會內聯所有的final方法,內聯對於提升Java運行效率作用重大,此舉能夠使性能平均提高50%。
2)盡量重用對象。由於Java虛擬機不僅要花時間生成對象,以後可能還需要花時間對這些對象進行垃圾回收和處理,因此生成過多的對象將會給程序的性能帶來很大的影響。
3)盡可能使用局部變數。調用方法時傳遞的參數以及在調用中創建的臨時變數都保存在棧中速度較快,其他變數,如靜態變數、實例變數等,都在堆中創建速度較慢。
4)慎用異常。異常對性能不利,只要有異常被拋出,Java虛擬機就必須調整調用堆棧,因為在處理過程中創建了一個新的對象。異常只能用於錯誤處理,不應該用來控製程序流程。
5)乘法和除法使用移位操作。用移位操作可以極大地提高性能,因為在計算機底層,對位的操作是最方便、最快的,但是移位操作雖然快,可能會使代碼不太好理解,因此最好加上相應的注釋。
6)盡量使用HashMap、ArrayList、StringBuilder,除非線程安全需要,否則不推薦使用 Hashtable、Vector、StringBuffer,後三者由於使用同步機制而導致了性能開銷。
盡量在合適的場合使用單例。使用單例可以減輕載入的負擔、縮短載入的時間、提高載入的效率,但並不是所有地方都適用於單例。
❸ java異常拋出異常後捕捉和不拋出直接捕捉有什麼區別
1.
其實拋出異常後應該就不能叫捕捉了
— 因為捕捉(即catch代碼塊)是在try代碼塊的後面執行的,然後你再throw一個Exception又是在catch代碼塊捕捉到異常後執行的,也是說順序是先try-->catch->throw;
2.
拋出異常異常後— 意味著catch代碼塊後面就不再執行了;
不拋出直接捕捉— 意味著catch代碼塊後面還會繼續執行。
ps:
不知道回答的對不對,不過希望對你有幫助。