2013年9月3日 星期二

Exception And Assertion


 
作者: 許裕永

程式執行時期,偶而會發生一些小錯誤,是可以體諒的。但是這個錯誤如果造成整個程式中斷,甚至電腦當機,那事情大條了。
到目前為止,我們所撰寫的程式碼,都沒有錯誤處理機制,也就是只要發生任何錯誤,程式便會中斷在發生錯誤的地方,而不會再繼續往下執行。假設我們準備把資 料儲存在檔案中,資料量很大,而在儲存到一半的時候,卻發生錯誤。此時因為資料還沒有儲存完畢,所以也就還沒有執行到close()這行敍述句來關閉檔 案。結果就是檔案中一片空白,什麼也沒有儲存到。但是如果我們可以在發生錯誤的時候,指定執行close(),那至少也儲存了一半的資枓。
這個在發生錯誤時,指定執行某些程式碼的機制,便稱之為錯誤處理機制。在英文中Exception翻譯為例外,所以也稱之為例外處理機制。但是因為這個機制並不是只能處理Exception,所以本書還是將之稱為錯誤處理機制。
Java中把程式執行時會發生的錯誤,區分為Exception及Error,本章討論的是Exception。因為會產生Error的狀況,大部份都是 執行程式的系統的問題(例:記憶體不足)。而這種錯誤也不是程式設計師所能改善的,我們能做的就是補捉這個Error然後顯示錯誤訊息。另外Error也 不列入SCJP認證範圍。
至於Assertion與Exception是完全沒有關係的,它是一個讓程式設計師設定中斷點,方便自行處理邏輯錯誤的一個機制。Assertion是開發時期的錯誤處理機制,而Exception是執行時期的錯誤處理機制。
 
1. Exception
Exception是一個類別名稱,它底下有許多的子類別分別代表各種不同狀況產生的錯誤。(繼承架構,讀者可先自行參閱JDK文件)
1-1 UnChecked Exception
假設有一個Exception名字叫A,目前撰寫的某一段程式碼,有可能會在執行時期產生A這個Exception而造成執行中斷。但是我們並沒有針對那 一段可能產生錯誤的程式碼,撰寫錯誤處理機制,而程式仍然可以編譯。那麼A這個Exception便屬於UnChecked Exception。
例一:
Scanner s=new Scanner(System.in);
int a=0;
System.out.print("請輸入任意整數-->");
a=s.nextInt();
System.out.println(100/a);
本例執行時若輸入整數數值,程式並不會有問題。但是若輸入的不是整數數值,程式便會中斷執行,並顯示下列訊息:
Exception in thread "main" java.util.InputMismatchException
at java.util.Scanner.throwFor(Unknown Source)
at java.util.Scanner.next(Unknown Source)
at java.util.Scanner.nextInt(Unknown Source)
at java.util.Scanner.nextInt(Unknown Source)
at JavaTest.main(JavaTest.java:8)
例二:
Scanner s=new Scanner(System.in);
int a=0;
System.out.print("請輸入任意整數-->");
a=s.nextInt();
System.out.println(100/a);
本例程式碼和例一一模一樣,只是執行時若輸入整數數值是0。則結果是:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at JavaTest.main(JavaTest.java:9)
例一的java.util.InputMismatchException以及例二的java.lang.ArithmeticException都不會影響程式碼的編譯,所以這兩個Exception均屬於UnChecked Exception。
由於UnChecked Exception不撰寫錯誤處理,程式也一樣可以編譯,所以設計師在學會錯誤處理之前,通常會用更嚴密的邏輯來撰寫程式碼(例 如用if判斷使用者輸入的值是否為0)以避免錯誤發生。在學會錯誤處理程式的撰寫後,可以自行分析用那一種寫法比較適當,來採取適當的寫法。
 
1-2 Checked Exception
假設有一個Exception名字叫B,目前撰寫的某一段程式碼,有可能會在執行時期產生B這個Exception而造成執行中斷。但是如果我們沒有針對 那一段可能產生錯誤的程式碼,做錯誤處理機制,程式在編譯時便會失敗。那麼B這個Exception便屬於Checked Exception。
例一:
Scanner s=new Scanner(new File("JavaTest.java"));
while(s.hasNextLine()){
 System.out.println(s.nextLine());
}
本例是在上一章中的範例程式碼,如果沒有撰寫錯誤處理機制,在編譯時會失敗,並顯示:
JavaTest.java:5: unreported exception java.io.FileNotFoundException; must be caught or declared to be thrown
在上一章中請讀者於main方法後方寫上throws來宣告FileNotFoundException就是一種錯誤處理機制。而沒有撰寫錯誤處理機制便無法編譯的Exception便屬於Checked Exception。
2. try catch finally
Exception是類別名稱,它的子類別代表著各種不同的錯誤。當Java執行的程式出現錯誤時,Java會把這個錯誤訊息建構成該錯誤訊息對應的Exception類別的物件,然後再把這個物件丟回程式之中,由程式來處理,若程式沒有處理便會中斷程式的執行。
所以請先建立正確的觀念:1、所謂產生Exception其實是建構了某一個Exception類別的物件。2、建構Exception物件的是Java。3、Exception物件會先傳回程式之中。
2-1 try catch
將可能會產生錯誤的程式碼寫在try的區塊中,再用catch來接收Java傳入的Exception物件。catch可以一個以上。
例一:
try{
 Scanner s=new Scanner(System.in);
 int a=0;

 System.out.print("請輸入任意整數-->");
 a=s.nextInt();
 System.out.println(100/a);
}catch(InputMismatchException e){
 System.out.println("請輸入整數數值");
}
本例執行時若使用者輸入非整數數值,則Java將會建構一個InputMismatchException類別的物件傳回程式中,於是catch便會補捉 這個物件並將之命名為e,然後便執行catch區塊中的程式碼。請注意:catch區塊執行完畢後,並不會再回頭去執行try區塊中未執行的程式碼。
 
例二:
try{
 Scanner s=new Scanner(System.in);
 int a=0;
 System.out.print("請輸入任意整數-->");
 a=s.nextInt();
 System.out.println(100/a);
}catch(InputMismatchException e){
 System.out.println("請輸入整數數值");
}catch(ArithmeticException e){
 System.out.println("請輸入非零數值");
}
本例使用不同的catch來補捉不同的Exception物件。因為只有一個catch區塊會執行,所以每個catch區塊中的變數名稱都是獨立的區域變數,所以兩個catch中的Exception都命名為e,是合法的。
 
例三:
try{
 Scanner s=new Scanner(System.in);
 int a=0;
 System.out.print("請輸入任意整數-->");
 a=s.nextInt();
 System.out.println(100/a);
}catch(InputMismatchException e){
 System.out.println("請輸入整數數值");
}catch(ArithmeticException e){
 System.out.println("請輸入非零數值");
}catch(Exception e){
 System.out.println("發生不明錯誤,程式即將關閉,若有問題,請洽系統管理人員");
}
本例再多用一個catch來補捉其他的Exception物件,畢竟到底使用者會做什麼蠢事,不是程式設計師可以完全防範的。至於這個區塊中要列印的訊 息,讀者可以自行變化。因為這是程式設計師的特權,程式錯誤看是要賴給系統管理師也好,網路工程師也罷。總之:千錯萬錯絕對不是程式設計師的錯。
但是本例中有一點要特別注意:Exception一定要放在最後一個catch,因為它是所有屬於Exception類別的父類別,若把它放在上面的catch,編譯會失敗。有關於父子類別的問題,讀者可以先不要管,後續章節中會介紹。
上面三個範例,主要是讓讀者了解基本的try catch的寫法。問題是:用try catch來處理上述的兩個Exception物件,真的有比較好 嗎?它只是讓程式死的優雅一點,但是並不能強迫使用者一定要輸入非零的整數值。反觀我們在上一章曾經用迴圈搭配hasNext及next來強迫使用者必須 輸入整數,否則迴圈不會結束。你覺得那一種比較適合呢?
這也是Java把這些Exception設定為UnChecked Exception的原因,不是不要處理,而是有時候用程式碼處理比用try catch好。
那讀者是不是要去背那一些Exception屬於UnChecked Exception,而那一些Exception又屬於 CheckedException呢?其實不必,關於UnChecked Exception只要程式邏輯嚴密一點,程式寫好後多做幾次測試,自然可以避 免。本章介紹的錯誤處理機制,基本上也不是為了UnChecked Exception來設計的。所以後續的範例便以Checked Exception 為主了。
 
例四:
try{
 Scanner s=new Scanner(new File("JavaTest.java"));
 PrintStream pw=new PrintStream("Copy_JavaTest.java");
 while(true){
  if(!s.hasNextLine())
  break;
  pw.println(s.nextLine());
 }
 pw.close();
}catch(FileNotFoundException e){
 System.out.println("檔案不存在");
}catch(IOException e){
 System.out.println("輸入或輸出時發生錯誤,請檢查磁碟系統");
}catch(Exception e){
 System.out.println("發生不明錯誤,程式即將關閉,若有問題,請洽系統管理人員");
}
本例是上一章中示範檔案複製的範例,當初我們把Exception類別名稱宣告於throws後面只是權宜之計,這種寫法才比較正統。
本例另一個重點是,三個catch的順序不能錯置,因為Exception是IOException的父類別,而IOException是FileNotFoundException的父類別。總之,父類別要置於子類別下方。(不懂沒有關係,先死記)
 
2-2 try catch finally
假設try區塊中有10行程式碼,當其中第三行程式出錯時,第四行以下的程式碼便沒有機會執行了。但是如果我們希望第八行至第十行程式碼,無論第三行程式碼是否出錯,都一定要執行呢?
我們可以把一定要執行的程式碼,寫在try catch結果之後,也就是不把那程式碼寫在try catch機制之中。但是就程式碼架構來看,是不適當的。因為直覺上會認為兩段程式碼是沒有關聯的。
所以,我們應該要把跟try區塊中的程式碼有關聯,而且一定要執行的程式敍述,寫在finally的區塊中。
例一:
int a=10;
try{
 a=a/0;
}catch(ArithmeticException e){
}finally{
 System.out.println(a);
}
列印結果:10。
示範主題:1、如果變數a宣告在try的區塊中,那麼變數a就只存活在try的區塊,無論是catch或finally都不能存取。2、catch的區塊中,不一定要有程式碼。3、catch的區塊可以有一個以上。
 
2-3 try finally
try區塊後可以直接寫finally,而不寫任何catch。
例一:
int a=10;
try{
 a=a/0;
}finally{
 System.out.println(a);
}
列印結果:10以及
Exception in thread "main" java.lang.ArithmeticException: / by zero
示範主題:會先執行finally再中斷程式。
 
2-4 巢狀try catch
如同if跟for一樣,try catch也可以是巢狀的。
例一:
BufferedReader br=null;
try{
 br=new BufferedReader(new FileReader("JavaTest.java"));
 String temp=null;
 while((temp=br.readLine())!=null){
  System.out.println(temp);
 }
}catch(FileNotFoundException e){
 System.out.println("檔案不存在");
}catch(IOException e){
 System.out.println("輸入或輸出時發生錯誤,請檢查磁碟系統");
}catch(Exception e){
 System.out.println("發生不明錯誤,程式即將關閉,若有問題,請洽系統管理人員");
}finally{
 try{
  br.close();
 }catch(IOException e){
  System.out.println("輸入或輸出時發生錯誤,請檢查磁碟系統");
 }
}
一般而言,關於輸入或輸出檔案內容的程式碼,大家都會想到要把檔案關閉的程式碼close寫在finally的區塊中,這樣才能在程式發生錯誤時把檔案關閉。
示範主題:1、BufferedReader型別的參考變數br,一定要宣告在try區塊之外,而且一定要指派(null也可以)。因為Java會把撰寫 在try區塊中的程式碼視為不一定會執行的程式碼。但是在finally中的程式碼“br‧close()卻一定會執行。如果br沒有指派,有可能造成 br沒有指派,卻呼叫方法的狀況,所以編譯不會成功。2、因為br‧close()也是會產生IOException的程式碼,所以一定要放在try的區 塊之中。
 
3. throws 與 throw
什麼樣的程式碼會產生Checked Exception呢?一定要編譯時才能知道嗎?當然不是。以上一節的範例而言,我們用到的是 java‧io‧BufferedReader。讀者可以在JDK文件中找到這個類別,再從Method Summary中找到close()及 readLine()的方法,再按下這兩個方法的超連結,便可以看到這兩個方法的語法說明,其中它們的方法原型是:
public void close() throws IOException

public String readLine() throws IOException
throws是一種宣告,它宣告本方法中的程式碼可能會丟出的Checked Exception,而因為是Checked Exception所以呼叫 本方法的敍述句,必須做錯誤處理機制。所以close()及readLine()都必須置於try的區塊之中。再用catch來補捉 IOException。
該範例中還有呼叫FileReader類別的建構方法,它的原型是: 
public FileReader(File file) throws FileNotFoundException
也就是用File物件為參數建構FileReader物件的敍述句,也必須置於try區塊之中。再用catch來補捉FileNotFoundException。
總而言之,程式碼中呼叫的方法,若有宣告throws CheckedException,就必須把該方法的呼叫敍述句置於try的區塊。
以上討論的是,呼叫方法時的錯誤處理機制,接下來要討論的是,設計師自行開發方法時,如何讓方法丟出指定的Check Exception物件,所以對於開發方法完全沒有概念的讀者,可以先略過本章剩下的內容,日後學到方法開發後再回來看。
 
3-1 throws
方法中如果有丟出Checked Exception物件的敍述句,則必須在方法名稱後以throws宣告。
丟出Checked Exception的方式有兩種。第一種是:呼叫有宣告throws ChecdedException的方法,而該呼叫敍述沒有置放於try catch的機制之中。
例一:
import java.io.*;
import java.util.*;
public class JavaTest{
 public static void main(String[] args){
  try{
   readFile();
  }catch(FileNotFoundException e){
   System.out.println("檔案不存在");
  }catch(IOException e){
   System.out.println("輸入或輸出時發生錯誤,請檢查磁碟系統");
  }catch(Exception e){
   System.out.println("發生不明錯誤,程式即將關閉,若有問題,請洽系統管理人員");
  }
 }
 public static void readFile()throws FileNotFoundException,IOException{
  BufferedReader br=new BufferedReader(new FileReader("JavaTest.java"));
  String temp=null;
  while((temp=br.readLine())!=null){
   System.out.println(temp);
  }
  br.close();
 }
}
本例中,新增了一個readFile的方法,在這個方法中我們撰寫了敍述句,來呼叫會丟出Checked Exception的一些方法,但這些敍述句都 沒有置於try catch機制之中。所以呼叫的這一些方法,它們會“丟出來”的Checked Exception就變成了本方法會“丟出去”的 Checked Exception。所以本方法就必須在方法名稱後面用throws宣告 FileNotFoundException,IOException。
那誰來處理本方法丟出去的Checked Exception呢?當然就是撰寫呼叫本方法敍述句的方法囉!在本例中就是main()。因為本方法是一個有宣告throws CheckedException 的方法,所以呼叫本方法的敍述句就必須置於錯誤處理機制之中。
之前我們曾經把Checked Exception宣告於main()方法的後面。這就等於是在宣告main()這個方法會丟出Checked  Exception。也就是呼叫main()這個方法的敍述句必須置於錯誤處理機制之中才不會造成程式中斷。問題是,誰呼叫main()?是Java。它 會寫try catch?會就有鬼了。所以,之前的程式之所以可以正常執行,是因為沒有真的發生錯誤。讀者可以試著讀一個不存在的檔案,保證程式中斷。所 以在main()後面throws CheckedException是個權宜之計,只是為了教學方便,其實是不合理的。
日後讀者們在開發方法時,就可以理解。與其每一個方法中都用try catch去補捉Exception。不如把它們throws出來,於整合呼叫的方法中(例如:main),再用try catch統一處理,效率上好太多了。
講了這麼多,其實規則只有兩條:
  1. 财 方法中不想丟出去的Checked Exception應該自行用try catch處理。
  2. 财 方法中想丟出去的Checked Exception必須在方法名稱後面用throws宣告。(用‘,’隔開可以宣告一個以上)
3-2 throw
方法中要丟出Checked Exception物件的方式有兩種:一種是:呼叫有宣告throws CheckedException的方法。另一種就是:在程式碼中用throw指定丟出的Exception物件。
而throw可以丟出的Exception物件,不管是UnChecked或Checked的Exception都可以。只是,如果是Checked  Exception就一定要宣告於throws的後面;但如果是UnChecked Exception則是否宣告於throws後面都可以。
例一:
public static void main(String[] args){
 int a=0;
 if(a==0)
  throw new NumberFormatException();
}
列印結果:Exception in thread "main" java.lang.NumberFormatException
at JavaTest.main(JavaTest.java:7)
程式丟出了throw指定的“物件”。
 
例二:
public static void main(String[] args)throws FileNotFoundException{
 int a=0;
 if(a==0)
  throw new FileNotFoundException();
}
列印結果:Exception in thread "main" java.io.FileNotFoundException
at JavaTest.main(JavaTest.java:7)
因為FileNotFoundException是Checked Exception所以必須在main方法後用throws宣告。
這種機制是讓設計師可以針對某一些狀況用指定的Exception物件丟出。在整合程式中,用catch補捉之後,就可以針對該類狀況做統一的處理。而若能搭配下一節的自訂Exception物件使用,那就更完美了。
 
4. 自訂Exception物件
本節內容屬於類別繼承的範圍,各位讀者稍做瀏覽或略過均可。
在第一節中我們曾提到:Exception是一個類別名稱,它底下有許多的子類別分別代表各種不同狀況產生的錯誤。現在我們可以自己設計一個Exception的子類別,來代表某一種自訂狀況的發生。
4-1 extends
基本語法: class ClassName extends Exception{}
只要把ClassName改成自訂的類別名稱,便是一個自訂的Exception類別。
例一:
public class ExceptionTest{
 public static void main(String[] args){
  try{
   test();
  }catch(MyException e){
   System.out.println("已接到MyException物件");
  }
 }
 public static void test()throws MyException{
  int a=0;
  if(a==0)
   throw new MyException();
 }
}
class MyException extends Exception{}
在MyException中,我們當然可以設計一些訊息,不過這我們會在後續類別設計的章節中學到,不是現在的重點。現在的重點還是在test()中的程 式碼。我們設定了某一種狀況成立的時候,便會丟出一個MyException物件。而因為自訂的Exception均屬於Checked  Exception,所以一定要在test()方法名稱後面,用throws宣告。
 
5. Assertion
有沒有過程式碼編譯沒有問題,但是執行的結果卻有時候對,有時候錯?如果每次都錯,那設計師要除錯還好一點。徧徧有時對,有時錯,這才討厭。
寫大程式,每個類別分開設計時,執行都對。等到整合起來,又是有時對,有時錯,昏倒。
總而言之,防呆。防呆有兩種:一種是防使用者的呆,例如前幾節介紹的Exception,大部份都是執行時,因為使用者的系統有問題,或使用者給錯資料,才會產生Exception;另一種是防自己的呆。
上面講的有時對,有時錯,這是程式碼的邏輯錯誤。有可能是流程控制的問題,也有可能是運算式的問題。這跟使用者給的值或使用者的系統是無關的。而這種錯是 最難除的。各位想想看:要寫一支大樂透的包牌程式(給任意個數字,6個一組共有幾種排列方式),需要幾行運算式?其中一行錯了,結果當然不對,但到底是那 一行錯了?怎麼找?
Assertion機制就是Java提供給設計師的程式碼除錯機制。請注意:它和Exception的除錯機制無關,請不要用try catch來處理這種錯誤。
 
5-1 assert
基本語法:assert 運算式A[:運算式B];
運算式A:運算結果為布林值的運算式,若運算值為false則中斷程式並丟出java‧lang‧AssertError。
運算式B:運算結果為字串(或可以自動轉換為字串)的運算式。也可以是呼叫方法的敍述句,但是該方法一定要有運算結果(不可以是void)。本運算式的值就是DOS視窗中所顯示的錯誤訊息,可以省略。
 
5-2 啟動指令
範例程式碼還沒寫,是因為寫了也看不出效果。為什麼呢?請注意,我們一直強調這個機制是在防設計師的呆。所以程式在執行時,預設是不會執行assert這 個指令的。所以設計師想要在執行時指定執行assert,就必須在執行指令(java)後面,加上開啟Assertion機制的參數。而因為一般使用者並 不懂這些指令,所以他們執行時,Assertion機制預設是關閉的。
執行指令及參數樣式
開啟或關閉Assertion機制
java -eajava -enableassertions 開啟Assertion機制。
java –dajava –disableassertions 關閉Assertion機制。因為預設就是關閉,所以幾乎沒有用到。
java –ea:com.yung.Bad 只開啟指定類別的Assertion機制。
java –ea:com.yung… 開啟指定package中,所有類別的Assertion機制。
java –ea –dsa 開啟Assertion機制,但關閉系統的相關類別的Assertion機制。
java –ea –da:com.yung… 開啟Assertion機制,但關閉指定package中,所有類別的Assertion機制。
從上表可以知道,Assertion機制的開啟及關閉是相當具有彈性,可以指定類別或package開啟;也可以指定開啟的同時又指定部份的類別或package關閉。
 
例一:
Scanner s=new Scanner(System.in);
System.out.print("請輸入任意整數-->");
int value=s.nextInt();
int a=value/100;
assert a!=0;
int b=123/a;
System.out.println(b);
請大家發揮想像力,讓我們把“int a=value/100;”這一行想像成是100行程式碼。也就是:「這100行運算式的運算結果,不可以是0,否 則“int b=123/a;”便會產生錯誤」。所以我們用Assertion機制來測試這100行程式執行的結果。如果在某些狀況之下真的程式中斷,就 表示這100行中,有某些地方出問題。此時,我們可以在這100行之中,另外再設一個中斷點,也就是再找一個變數,用assert來測試它的值是否正常。 比如說這個新的中斷點是設在第50行的位置,而這個新的中斷點測試後卻沒有問題。我們就可以肯定是第51至第100行中的某個地方出問題。然後我們再於第 51行至第100行當中,設定新的中斷點來測試。以此循還,可以協助我們比較有效率的找出邏輯錯誤的地方,而不必老是盯著螢幕用大腦去運算。總之: 「Assertion機制是讓設計師設定程式中斷點,來協助處理邏輯錯誤的機制」。
這個時候,有些讀者可能會想起if。但是,請記得,我們現在是在除自己的錯,這個除錯機制我們並不希望在使用者執行的時候執行。如果寫成if就沒有辦法讓 使用者不執行,除非測試完後我們把它刪掉。但如果測試點很多,刪起來就很麻煩,萬一刪掉了程式還是不對又要再寫上去,就更麻煩。但如果使用 Assertion機制,測試完這些敍述句不必刪除,如果改天要擴充程式碼時,還可以繼續用,這才方便。
現在我們在兩行敍述句的中間,加上“assert a!=0;”。這樣,我們就可以開始測試程式,看看在什麼狀況下程式會中斷,再來修改程式。
執行時請輸入:java -ea 執行檔案名稱
在上例中程式中斷時,DOS視窗會顯示:
Exception in thread “main” java.lang.AssertionError
 
例二:
Scanner s=new Scanner(System.in);
System.out.print(“請輸入任意整數à”);
int value=s.nextInt();
int a=value/100;
assert a!=0:value;
int b=123/a;
System.out.println(b);
此例中的assert敍述改為asset a!=0:value;則執行時若程式中斷時,DOS視窗會顯示:
Exception in thread “main” java.lang.AssertionError: 80
也就是在會把value的值做為錯誤訊息,列印於‘:’之後。
大家可以再多練習幾次,來體會這個機制的使用方式。它是在條件值為true時繼續執行,條件值為false時中斷程式。也就是:「條件值是設計師預期要的值,而當執行時期該值不符合設計師的期望時,中斷程式」。
 
5-3 適當的使用時機
在探討Assertion機制使用時機之前,我們再確認兩個觀念:1、Assertion機制在使用者執行時,是肯定關閉的,因為使用者不會去開啟它,也 沒有必要。2、Assertion機制所產生的error是用來中斷程式,協助我們除錯,請不要把它當做另一種if的語法來寫,更不要用try  catch的機制來補捉這個AssertionError。
以下的使用時機,是一種建議,而不是規定。違反建議並不會造成編譯錯誤,但可能會造成另類的邏輯錯誤。(關於方法參數的部份,後續章節介紹)
  1. 不要在assert中執行必要的運算。
    因為assert在執行時期是不執行的,如果我們在assert的敍述中執行必要運算,那麼這個運算在執行時期是不會運算的。
  2. 不要用Assertion機制來檢測public方法的參數。
    宣告為public的方法,表示要類別使用者接受呼叫,既然要接受呼叫,那麼參數的檢測是一定要做的程序,應該用if而不是用assert。
  3. 不要用Assertion機制來檢測方法的運算結果。
    程式碼中呼叫某一個方法並取得它的運算結果後,自然要檢測它的運算結果是否符合我們程式的要求,應該用if而不是用assert。
  4. 建議使用Assertion機制來檢測private方法的參數。
    宣告為private的方法只能在類別內部中呼叫,也就是呼叫的是開發這個類別的你,並未公開,所以很適合用assert來檢測參數。
  5. 建議使用在switch的語法,來了解case不成立的原因。
    在switch的語法中,如果所有case都不成立,便會執行default的敍述區,但到底為什麼所有case都不成立,就非常適合用Assertion機制來了解。
  6.  程式碼重點的標註。
    Assertion機制,不只是在程式碼寫完執行有問題之後才使用。在撰寫程式碼的同時,在程式碼重要的轉折點便應該撰寫assert來保障程式碼的程式 不會徧離設計師的期望。而撰寫的這些assert在程式完成後不必刪除,可以留給後續程式再擴充或專案管理時(不論管理者是否是開發程式的人),都可以立 刻了解程式的重點,以及修改程式碼時,應該注意的事項。
6. 認證重點整理
6-1 Exception
  • 财 Assertion是開發時期的錯誤處理機制,而Exception是執行時期的錯誤處理機制。
  • 财 Exception是一個類別名稱,它底下有許多的子類別分別代表各種不同狀況產生的錯誤。
  • 财 沒有撰寫錯誤處理,而程式一樣可以編譯的Exception屬於UnCheck Exception。
  • 财 沒有撰寫錯誤處理,程式就無法編譯的Exception屬於Check Exception。
  • 财 觀念:1、所謂產生Exception其實是建構了某一個Exception類別的物件。2、建立Exception物件的是Java。3、Exception物件會先傳回程式之中。
6-2 try catch finally
  • 财 將可能會產生錯誤的程式碼寫在try的區塊中,再用catch來接收Java傳入的Exception物件。catch可以一個以上。
  • 财 catch區塊執行完畢後,並不會再回頭去執行try區塊中未執行的程式碼。
  • 财 Exception在catch中的排列,父類別要置於子類別下方。
  • 财 我們應該要把跟try區塊中的程式碼有關聯,而且一定要執行的程式碼,寫在finally的區塊中。
  • 财 如果變數a宣告在try的區塊中,那麼變數a就只存活在try的區塊,無論是catch或finally的區塊都不能存取。
  • 财 try區塊後可以直接寫finally,而不寫任何catch。
  • 财 如同if跟for一樣,try catch也可以是巢狀的。
  • 财 try catch finall是整體,各個區塊之間,不可以撰寫任何敍述句。

6-3 throws 與 throw
  • 财 方法中如果有丟出Checked Exception物件的敍述句,則必須在方法名稱後以throws宣告。
  • 财 丟出Checked Exception的方式有兩種。第一種是:呼叫有宣告throws ChecdedException的方法,而該呼叫敍述沒有置放於try catch的機制之中。另一種就是:在程式碼中用throw指定丟出的Exception物件。
  • 财 方法中不想丟出去的Checked Exception應該自行用try catch處理。
  • 财 方法中想丟出去的Checked Exception必須在方法名稱後面用throws宣告。
  • 财 throw可以丟出的Exception物件,不管是UnChecked或Checked的Exception都可以。只是,如果是Checked  Exception就一定要宣告於throws的後面;但如果是UnChecked Exception則是否宣告於throws後方都可以。
6-4 自訂Exception
  • 财 自訂的Exception均屬於Checked Exception。
6-5 Assertion
  • 财 Assertion機制的開啟及關閉是相當具有彈性,可以指定類別或package開啟;也可以指定開啟的同時又指定部份的類別或package關閉。
  • 财 Assertion機制是讓設計師設定程式中斷點,來協助處理邏輯錯誤的機制。
  • 财 assert是在條件值為true時繼續執行,條件值為false時中斷程式。也就是條件值應該是設計師預期要的值,而當執行時期該值不符合設計師的期望時,中斷程式。
  • 财 Assertion機制在使用者執行時,是肯定關閉的,因為使用者不會去開啟它,也沒有必要。
  • 财 Assertion機制所產生的error是用來中斷程式,協助我們除錯,請不要把它當做另一種if的語法來寫,更不要用try catch的機制來補捉這個AssertionError。
  • 财 不要在assert中執行必要的運算。
  • 财 不要用Assertion機制來檢測public方法的參數。
  • 财 不要用Assertion機制來檢測方法的運算結果。
  • 财 建議使用Assertion機制來檢測private方法的參數。
  • 财 建議使用在switch的語法中,來了解case不成立的原因。

沒有留言:

張貼留言

注意:只有此網誌的成員可以留言。