java的異常處理涉及到程式流程的跳轉,所以,虛擬機器需要儲存程式的執行流程,以便異常發生時能正確的跳轉,這也就導致了使用異常時會引起額外的開銷,所以,要謹慎地使用異常。
使用異常有如下幾個原則:
1、盡量避免使用異常,將異常情況提前檢測出來。
2、不要為每個可能會出現異常的語句都設定try和catch。
3、避免在方法中拋出(throw)或者捕獲(catch)運行時異常RuntimeException和Error。
4、避免總是catch Exception或Throwable,而要catch具體的異常類。這樣可以使程式更加清晰。
5、不要壓制、隱瞞異常。將不能處理的異常往外拋,而不是捕獲之後隨便處理。
6、不要在迴圈中使用try...catch,盡量將try...catch放在迴圈外或者避免使用。
7、在catch Exception中不只要處理異常,有時還要出棧、對前面的一些變數進行處理,否則可能出現bug
示範執行個體
package book.exception;
import java.util.Date;
import java.util.EmptyStackException;
import java.util.Stack;
/** *//**
* 使用異常的幾點注意
* @author joe
*
*/
public class ExceptionTips ...{
public static void main(String[] args) ...{
//(1)盡量避免使用異常,將異常情況提前檢測出來
Stack<Object> stack = new Stack();
try...{
stack.pop();
} catch (EmptyStackException e) ...{
//....
}
//應該用下面的方式,以避免使用異常
if (!stack.isEmpty()) ...{
stack.pop();
}
//(2)不要為每個可能會出現的一場的語句都設定try和catch
try...{
stack.pop();
} catch (EmptyStackException e) ...{
//....
}
String data = "123";
try ...{
Double.parseDouble(data);
} catch(NumberFormatException e)...{
//....
}
//應該使用下面的方式,將兩個語句放在一個try塊中
try...{
stack.pop();
Double.parseDouble(data);
} catch(EmptyStackException e) ...{
//....
} catch(NumberFormatException e) ...{
//....
}
//(3)避免在方法中拋出或者捕獲運行時異常RuntimeException和Error,
//比如記憶體錯誤等
//避免出現下面的情況
String[] array;
try ...{
array = new String[1000];
//array = new String[1000000];此時會出現OutOfMemoryError異常
} catch (OutOfMemoryError e) ...{
throw e;
}
//直接用下面代碼
array = new String[1000];
//(4)避免總是catch Exception或Throwable,而要捕獲具體的異常
//這樣可以根據不同的異常做不同的處理,使程式更加清晰
try ...{
stack.pop();
Double.parseDouble(data);
} catch (Exception e) ...{
//應該避免catch Exception !!!
}
//(5)不要壓制、隱瞞異常。將不能處理的異常往外拋,而不是捕獲之後隨便處理
try...{
Double.parseDouble(data);
} catch (NumberFormatException e) ...{
//.....
throw e; //拋出不能處理的異常,而不是隱瞞
}
//(6)不要在迴圈中使用try catch,盡量將try catch放在迴圈外或者避免使用try catch
//下面的例子在迴圈中使用try和catch將耗費更多的時間,儘管沒有異常發生
int i = 0;
int ntry = 1000000;
Stack s = new Stack();
long s1;
long s2;
System.out.println("Testing for empty stack");
s1 = new Date().getTime();
for (i = 0; i <= ntry; i++) ...{
if (!s.empty()) ...{
s.pop();
}
}
s2 = new Date().getTime();
System.out.println((s2 - s1) + "milliseconds");
System.out.println("Catching EmptyStackException");
s1 = new Date().getTime();
for(i = 0; i<=ntry; i++) ...{
try ...{
s.pop();
} catch(EmptyStackException e) ...{
}
}
s2 = new Date().getTime();
System.out.println((s2 - s1) + "milliseconds");
}
}
程式輸出:
Testing for empty stack
63milliseconds
Catching EmptyStackException
1922milliseconds
這樣的錯誤以前我也犯過,也見過不少人這樣的寫法。下面我也舉個例子:
public void writeFile(File f) {
String content = null;
try {
byte[] b = new byte[1024];
FileInputStream in = new FileInputStream(f);
in.read(b);
content = new String(b);
} catch (Exception e) {
System.out.println(e.getMessage());
}
if (content.indexOf("hello") > -1) {
System.out.println("yes");
} else {
System.out.println("no");
}
}
上面是個簡單的方法,代碼中有個隱藏的bug。我在維護一個系統的時候就遇到類似的代碼,實際中類似的BUG隱藏
的更深。在對系統業務和代碼不是很很熟悉的情況下,我推薦如下寫法:
public void writeFile(File f) {
String content = null;
try {
byte[] b = new byte[1024];
FileInputStream in = new FileInputStream(f);
in.read(b);
content = new String(b);
} catch (Exception e) {
content="";
//如果異常發生的話,content可能為空白
//下面對content的操作就有可能發生NullPointerException異常
System.out.println(e.getMessage());
}
//下面操作有可能發生NullPointerException異常
if (content.indexOf("hello") > -1) {
System.out.println("yes");
} else {
System.out.println("no");
}
}