java異常及錯誤處理大綱
文章目錄
1.異常處理
異常(exception ) 又稱為例外、差錯、違例
對應著Java執行錯誤處理機制
基本寫法
try{
語句組
}catch(Exception ex){
異常處理語句組;
}
import java.io.*;
public class ExceptionForNum
{
public static void main(String[] args)
{
try {
BufferedReader in = new BufferedReader(
new InputStreamReader( System.in ) );
System.out.print("Please input a number: ");
String s = in.readLine();
int n = Integer.parseInt( s );
}catch(IOException ex){
ex.printStackTrace();
}catch(NumberFormatException ex){
ex.printStackTrace ();
}
}
}
傳統的 語言如何處理
在一些傳統的語言(如C語言中)
if語句來判斷是否出現了例外
全程變數ErrNo
但這有幾個缺點
正常處理與異常處理的程式碼同樣處理
可讀性(readability)差
每次呼叫一個方法時都進行錯誤檢查
可維護性( maintainability )差
錯誤由誰處理不請
職責不清
Java中處理異常
丟擲(throw)異常
執行時系統在呼叫棧中查詢
從生成異常的方法開始進行回溯,直到找到:
捕獲(catch) 異常的程式碼
相關的語句
丟擲異常
throw 異常物件;
捕獲異常
try {
語句組
}catch(異常類名 異常形式引數名){
異常處理語句組;
}catch(異常類名 異常形式引數名){
異常處理語句組;
}finally{
異常處理語句組;
}
其中,catch語句可以0至多個,可以沒有finally語句
異常的分類
Throwable (可丟擲)
Error: JVM的錯誤
Exception: 異常
一般所說的異常
是指Exception及其子類
Exception類
構造方法
public Exception();
public Exception(String message);
Exception(String message, Throwable cause) ;
方法
getMessage()
getCause()
printStackTrace()
多異常的處理
子類異常要排在父類異常的前面
finally語句
無論是否有異常都要執行
即使其中有break,return等語句
在編譯時,finally部分程式碼生成了多遍
package ch5;
public class text1 {
public static String output = "";
public static void foo(int i) {
try {
if (i == 1) {
throw new Exception();
}
output += "1";
} catch(Exception e) {
output += "2";
return;
} finally {
output += "3";
}
output += "4";
}
public static void main(String args[]) {
//foo(0);
//System.out.print(output + " ");
foo(1);
System.out.println(output);
}
}
//最後結果是23這說明,不管之前catch裡是什麼語句,都會執行finally語句
Exception分兩種
RuntimeException及其子類,可以不明確處理
否則,稱為受檢的異常(checked Exception)
受檢的異常,要求明確進行語法處理
要麼捕(catch)
要麼拋(throws):在方法的簽名後面用throws xxxx來宣告
在子類中,如果要覆蓋父類的一個方法,若父類中的方法聲明瞭 throws異常,則子類的方法也可以throws異常
可以丟擲子類異常(更具體的異常),但不能丟擲更一般的異常
package ch5;
import java.io.FileInputStream;
import java.io.IOException;
public class text1{
public static void main(String[] args){
try{
System.out.println("====Before====");
readFile();
System.out.println("====After====");
}catch(IOException e){ System.out.println(e); }
}
public static void readFile()throws IOException {
FileInputStream in=new FileInputStream("myfile.txt");
int b;
b = in.read();
while(b!= -1) {
System.out.print((char)b);
b = in.read();
}
in.close();
}
}
try…with…resource
try(型別 變數名 = new 型別() ){
。。。
}
自動添加了finally{ 變數.close(); }
不論是否出現異常,都會執行
package ch5;
import java.io.*;
class TryWithResourcesTest {
public static void main(String ... args)
throws IOException
{
String path = "c:\\aaa.txt";
System.out.println( ReadOneLine1( path ) );
System.out.println( ReadOneLine2( path ) );
}
static String ReadOneLine1(String path){
BufferedReader br=null;
try {
br=new BufferedReader(new FileReader(path));
return br.readLine();
} catch(IOException e) {
e.printStackTrace();
} finally {
if(br!=null){
try{
br.close();
}catch(IOException ex){
}
}
}
return null;
}
static String ReadOneLine2(String path)
throws IOException
{
try(BufferedReader br= new BufferedReader(new FileReader(path))){
return br.readLine();
}
}
}
2. 自定義異常
建立使用者自定義異常類
建立使用者自定義異常時
(1) 繼承自Exception類或某個子Exception類
(2) 定義屬性和方法,或過載父類的方法
重拋異常及異常連結
對於異常,不僅要進行捕獲處理,有時候還需要將此異常進一步傳遞給呼叫者,以 便讓呼叫者也能感受到這種異常。這時可以在catch語句塊或finally語句塊中採取 以下三種方式:
(1)將當前捕獲的異常再次丟擲:
throw e;
(2)重新生成一個異常,並丟擲,如:
throw new Exception(“some message”);
(3)重新生成並丟擲一個新異常,該異常中包含了當前異常的資訊,如:
throw new Exception(“some message”,e);
可用e.getCause() 來得到內部異常
public class ExceptionCause {
public static void main(String [] args) {
try
{
BankATM.GetBalanceInfo( 12345L);
}catch(Exception e) {
System.out.println("something wrong�� " + e);
System.out.println("cause��" + e.getCause());
}
}
}
class DataHouse {
public static void FindData( long ID)
throws DataHouseException
{
if( ID>0 && ID<1000)
System.out.println( "id: " + ID );
else
throw new DataHouseException("cannot find the id");
}
}
class BankATM{
public static void GetBalanceInfo( long ID)
throws MyAppException
{
try
{
DataHouse.FindData(ID);
}catch (DataHouseException e) {
throw new MyAppException("invalid id",e);
}
}
}
class DataHouseException extends Exception {
public DataHouseException( String message ) {
super(message);
}
}
class MyAppException extends Exception {
public MyAppException (String message){
super (message);
}
public MyAppException (String message, Exception cause) {
super(message,cause);
}
}
3. 斷言及程式的測試
斷言(assertion)
assert的格式是:
assert 表示式; (邏輯表示式)
assert 表示式 : 資訊;
在除錯程式時
如果表示式不為true,則程式會產生異常,並輸出相關的錯誤資訊
class Assertion {
public static void main(String[] args) {
assert hypotenuse(3,4)==5 : "演算法不正確";
}
static double hypotenuse( double x, double y ){
return Math.sqrt( x*x + y*y + 1);
}
}
Assert 的編譯及執行
編譯
只有在JDK1.4及以上的版本中才可以使用斷言。
具體地說,在早期的JDK版本(1.4)中編譯時,要通過-source選項來指明版本,如:
javac -deprecation -source 1.4 -classpath . Assertion.java
執行
在執行時,要使assert起作用,則在java命令中,使用選項(-ea,即-enableassertions)。如:
java -ea -classpath . Assertion
程式的測試及 JUnit
程式的修改是經常要進行的過程,必須保證程式在修改後其結果仍然 是正確的。
在編寫程式程式碼的同時,還編寫測試程式碼來判斷這些程式是否正確。
這個過程稱為“測試驅動”的開發過程。
從而保證了程式碼的質量,減少了後期的查錯與除錯的時間,所以實際 上它提高了程式的開發效率。
JUnit
在Java的測試過程,經常使用JUnit框架
參見http://www.junit.org。
現在大多數Java整合開發工具都提供了對JUnit的支援。
在Eclipse中
專案右鍵—New— Junit Test Case
專案右鍵—Run as — Junit Test
測試通過則為綠色,不通過顯示紅色
在NetBeans中
專案右鍵—新建— Junit測試
執行—測試,或者直接按Alt+F6即可
測試函式
@Test來標註測試函式
在測試中常用的語句如下:
fail( 資訊 ); //表示程式出錯
assertEqauls(引數1,引數2 ); //表示程式要保證兩個引數要相等
assertNull(引數); //表示引數要為null
@Test
public void testSum2() {
HelloWorld a = new HelloWorld();
assertEquals(a.sum(0, 100), 100);
// fail("Not yet implemented");
}
4. 程式的除錯
程式中的錯誤
程式中的錯誤通常可以分成三大類
語法錯誤(Syntax error)
編輯、編譯器發現
執行錯誤(Runtime error)
異常處理機制
邏輯錯誤(Logic error)
除錯(debug) 、單元測試(unit test)
程式的除錯(debug)
在IDE中,專案上點右鍵 ,debug as…
進入到除錯檢視(debug perspective)
除錯的三種手段
斷點 (breakpoint)
跟蹤 (trace)
監視 (watch)
斷點
切換斷點(toggle breakpoint )
用滑鼠單擊(或右擊)編輯器左邊條
或者
Eclipse Ctrl+Shift+B
NetBeans Ctrl+F8
跟蹤
Eclipse | NetBeans | |
---|---|---|
逐語句執行 | F5 | F7 |
逐過程執行 | F6 | F8 |
跳出函式 | F7 | Ctrl+F7 |
執行到游標處 | Ctrl+R | F4 |
監視
即時監視
滑鼠指向變數
快速監視
點右鍵,Inspector
新增監視
點右鍵,Watch
還可以看:呼叫堆疊等等