Java:如何正确地使用异常详解
概述:
? Java中的異常機(jī)制是一個好東西。不過好東西也要正確地使用才行,不然就會讓我們錯誤地認(rèn)識它。在錯誤地認(rèn)識狀況下,就會錯誤地使用。這樣就成了一個惡性地循環(huán)了。這不是我們愿意看到的。不要以為我們已經(jīng)可以很好地使用異常了,下面就針對部分問題作一個講解。這部分的問題中,有一些是來自《Effective Java》這本書中,有一部分是來自本人平時開發(fā)過程中遇到的。
本文鏈接:http://blog.csdn.net/lemon_tree12138/article/details/50474230 -- Coding-Naga
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?--轉(zhuǎn)載請注明出處
1.是throw還是try-catch
? 這個是一個對剛接觸編程開發(fā)的人來說,經(jīng)常面臨但又選擇不好的問題。
? 由于我們開發(fā)的項目可不是像寫Demo一樣輕松,這里可能會有很多層次結(jié)構(gòu)。我們要在具體哪一層的什么位置是使用try-catch這個異常呢,還是把異常throw到上一層呢?這里,我們首先要知道一件事,那就是try-catch和throw分別會發(fā)生什么情況呢?
try-catch: 捕獲一個異常情況,并中止try塊中的后續(xù)操作。且不會再向上拋出異常了。
throw: 當(dāng)使用throw拋出一個異常時,當(dāng)前的執(zhí)行塊(方法)會結(jié)束后續(xù)的執(zhí)行。相當(dāng)于一個return操作,并保證了上層在調(diào)用的時候可以捕獲到這個異常,并做相應(yīng)處理。
Demo示例如下:
public class ExceptionClient {public static void main(String[] args) {ExceptionClient client = new ExceptionClient();client.showInfo();}private void showInfo() {try {System.out.println("first info");testException();System.out.println("second info");} catch (Exception e) {System.err.println(e);}System.out.println("outside info");}private void testException() throws AException {boolean f = true;if (f) {throw new AException("AException");}System.out.println("f is false.");} } ? 按照上面對try-catch和throw的分析,可以知道,showInfo方法try塊中的第二句話是不打印的,而testException方法的最后一句也是不打印的。結(jié)果如下:
圖-1 try-catch測試結(jié)果
2.是使用受檢的異常還是非受檢的異常
? 首先我們要了解什么是受檢異常和非受檢異常,不過這里顧名思義,受檢即接受檢查。由于目前的IDE很是智能,當(dāng)我們在使用受檢異常而未try-catch這個異常時,IDE會給出錯誤提示。如下:
圖-2 IDE對受檢異常的檢查
? 而非受檢異常則不會被IDE識別。還有一點,因為前面說到IDE會檢測到受檢異常,所以,這里如果我們強(qiáng)行運(yùn)行此代碼,是通不過編譯的,非受檢異常則不會。
? 好了,說明了受檢異常和非受檢異常在使用過程中的區(qū)別。現(xiàn)在就來說說怎么創(chuàng)建這些不同的異常吧。
? 當(dāng)我們要編寫自定義的受檢異常A.java時,A的class需要繼承Exception,而非受檢異常B.java則是繼承RuntimeException。
? 由于受檢異常會在使用的過程,強(qiáng)行限制開發(fā)人員去try-catch。而在try-catch此異常的時候,開發(fā)人員則可以對此異常進(jìn)行修正并重新之前的操作(即恢復(fù))。在RuntimeException中則沒有這樣的限制。所以,當(dāng)我們試圖告訴調(diào)用者,當(dāng)前的異常是可以被修復(fù),并允許重新去調(diào)用的時候,我們就使用受檢的異常,當(dāng)我們認(rèn)為這是一個程序錯誤的時候,則需要使用非受檢異常。
? 可能對在何時使用受檢異常或非受檢異常有了一些基本認(rèn)識,然后你可能會問這樣的一個問題:我們不是還有一個Error么,那么錯誤(Error)和異常有什么區(qū)別呢?下面就列舉了這兩者之間的區(qū)別(點擊查看參考來源):
Exception:
1.可以是可被控制(checked) 或不可控制的(unchecked)。
2.表示一個由程序員導(dǎo)致的錯誤。
3.應(yīng)該在應(yīng)用程序級被處理。
Error:
1.總是不可控制的(unchecked)。
2.經(jīng)常用來用于表示系統(tǒng)錯誤或低層資源的錯誤。
3.如何可能的話,應(yīng)該在系統(tǒng)級被捕捉。
3.只針對不正確的條件才使用異常
? 關(guān)于這一點,首先我們應(yīng)該了解的是Java在進(jìn)行異常檢查時消耗的系統(tǒng)資源,要比普通的程序調(diào)用高。那么,如果我們的程序在不停地進(jìn)行異常檢查,就會對程序整個的性能產(chǎn)生不小的影響。我們可以從一個小例子中看出這一點。如下:
假設(shè)現(xiàn)有10000000個元素的List,我們要對此List進(jìn)行遍歷,有三種方式,分別如下:
第一種:對每一種情況進(jìn)行異常檢查
private void call_1(List<Integer> list) {long t = System.currentTimeMillis();try {int index = 0;while(true) {list.get(index++);} } catch (IndexOutOfBoundsException e) {LogUtils.printTimeUsed("不針對檢查異常", t);}}
第二種:只對錯誤的情況進(jìn)行異常檢查
private void call_2(List<Integer> list) {long t = System.currentTimeMillis();t = System.currentTimeMillis();int size = list.size();int index = 0;while(true) {if (index >= size) {try {list.get(index++);} catch (IndexOutOfBoundsException e) {LogUtils.printTimeUsed("針對性檢查異常", t);break;}}list.get(index++);}}第三種:普通的循環(huán)遍歷
private void call_3(List<Integer> list) {long t = System.currentTimeMillis();t = System.currentTimeMillis();int size = list.size();int index = 0;for (index = 0; index < size; index++) {list.get(index++);}LogUtils.printTimeUsed("循環(huán)遍歷", t);}測試結(jié)果:
圖-3 不同異常檢查方式遍歷List
? 從上面的測試結(jié)果中,我們可以看到不針對地檢查異常(盲目地檢查異常),比有針對性地檢查異常性能上低了不少。所以,我們在使用異常的時候,請格外謹(jǐn)慎。需要去避免一些不必要的異常檢查,以優(yōu)化我們的程序代碼。
Ref:
《Effective?Java》
總結(jié)
以上是生活随笔為你收集整理的Java:如何正确地使用异常详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 操作系统:基于页面置换算法的缓存原理详解
- 下一篇: JSunpack-n的安装与简单使用