第二部分:流程控制,斷言和異常處理
第二部分:流程控制,斷言和異常處理
- 能夠正確使用if,switch語句,并且能正確使用合法的參數類型。
- 能夠正確使用所有帶標簽或不帶標簽的循環語句,能正確使用break,continue,能計算在循環中或循環后循環計數器的值。
- 能夠正確使用異常和異常處理語句(try,catch,finally)。能正確聲明拋出異常的方法,并知道怎樣覆蓋它。
- 了解代碼段中的異常對程序跳轉的影響。注意:異常可能是一個運行時異常(runtime
exception),一個已經定義的異常(checked exception),也可能是一個error。 - 能正確使用斷言,并了解關于斷言機制的正確說法。
- 能夠正確使用if,switch語句,并且能正確使用合法的參數類型。
- 能夠正確使用所有帶標簽或不帶標簽的循環語句,能正確使用break,continue,能計算在循環中或循環后循環計數器的值。
- 能夠正確使用異常和異常處理語句(try,catch,finally)。能正確聲明拋出異常的方法,并知道怎樣覆蓋它。
- 了解代碼段中的異常對程序跳轉的影響。注意:異常可能是一個運行時異常(runtime
exception),一個已經定義的異常(checked exception),也可能是一個error。 - 能正確使用斷言,并了解關于斷言機制的正確說法。
第一節 斷言 assert
§1.1.1 assertion 的語法和語義
J2SE 1.4在語言上提供了一個新特性,就是assertion(斷言)功能,它是該版本在Java語言方面最大的革新。在軟件開發中,assertion是一種經典的調試、測試方式,本文將深入解析assertion功能的使用以及其設計理念,并給出相關的例子。
assertion(斷言)在軟件開發中是一種常用的調試方式,很多開發語言中都支持這種機制,如C,C++和Eiffel等,但是支持的形式不盡相同,有的是通過語言本身、有的是通過庫函數等。另外,從理論上來說,通過assertion方式可以證明程序的正確性,但是這是一項相當復雜的工作,目前還沒有太多的實踐意義。
在實現中,assertion就是在程序中的一條語句,它對一個boolean表達式進行檢查,一個正確程序必須保證這個boolean表達式的值為true;如果該值為false,說明程序已經處于不正確的狀態下,系統將給出警告或退出。一般來說,assertion用于保證程序最基本、關鍵的正確性。assertion檢查通常在開發和測試時開啟。為了提高性能,在軟件發布后,assertion檢查通常是關閉的。下面簡單介紹一下Java中assertion的實現。
1.1) 語法表示
在語法上,為了支持assertion,Java增加了一個關鍵字assert。它包括兩種表達式,分別如下:
1.
2.
在兩種表達式中,expression_r1表示一個boolean表達式,expression_r2表示一個基本類型或者是一個對象(Object) ,基本類型包括boolean,char,double,float,int和long。由于所有類都為Object的子類,因此這個參數可以用于所有對象。
1.2) 語義含義
在運行時,如果關閉了assertion功能,這些語句將不起任何作用。如果打開了assertion功能,那么expression_r1的值將被計算,如果它的值為false,該語句強拋出一個AssertionError對象。如果assertion語句包括expression_r2參數,程序將計算出expression_r2的結果,然后將這個結果作為AssertionError的構造函數的參數,來創建AssertionError對象,并拋出該對象;如果expression_r1值為true,expression_r2將不被計算。
一種特殊情況是,如果在計算表達式時,表達式本身拋出Exception,那么assert將停止運行,而拋出這個Exception。
1.3) 一些assertion例子
下面是一些Assert的例子。
1.
2.
3.
4.
1.4) 編譯
由于assert是一個新關鍵字,使用老版本的JDK是無法編譯帶有assert的源程序。因此,我們必須使用JDK1.4(或者更新)的Java編譯器,在使用Javac命令時,我們必須加上-source 1.4作為參數。-source 1.4表示使用JDK 1.4版本的方式來編譯源代碼,否則編譯就不能通過,因為缺省的Javac編譯器使用JDK1.3的語法規則。
一個簡單的例子如下:
javac
1.5) 運行
由于帶有assert語句的程序運行時,使用了新的ClassLoader和Class類,因此,這種程序必須在JDK1.4(或者更高版本)的JRE下運行,而不能在老版本的JRE下運行。
1.
§1.1.2 assertion 的設計問題
首先,我們認為assertion是必要的。因為,如果沒有統一的assertion機制,Java程序通常使用if-then-else或者switch-case語句進行assertion檢查,而且檢查的數據類型也不完全相同。assertion機制讓Java程序員用統一的方式處理assertion問題,而不是按自己的方式處理。另外,如果用戶使用自己的方式進行檢查,那么這些代碼在發布以后仍然將起作用,這可能會影響程序的性能。而從語言言層次支持assertion功能,這將把assertion對性能帶來的負面影響降到最小。
Java是通過增強一個關鍵字assert實現支持assertion,而不是使用一個庫函數支持,這說明Java認為assertion對于語言本身來說是非常重要的。實際上,在Java的早期的規范中,Java是能夠支持assert的,但是由于一些實現的限制,這些特性從規范中除去了。因此,assert的再次引入應該是恢復了Java對assert的支持。C語言就是通過Assert.h函數庫實現斷言的支持。
Java的assertion的開啟也和C語言不太一樣,我們都知道在C語言中,assertion的開啟是在編譯時候決定的。當我們使用debug方式編譯程序時候,assertion被開啟,而使用release方式編譯時候,assertion自動被關閉。而Java的assertion卻是在運行的時候進行決定的。其實,這兩種方式是各有優缺點。如果采用編譯時決定方式,開發人員將處理兩種類型的目標碼,debug版本和release版本,這加大了文檔管理的難度,但是提高了代碼的運行效率。Java采用運行時決定的方式,這樣所有的assertion信息將置于目標代碼中,同一目標代碼可以選擇不同方式運行,增強目標代碼的靈活性,但是它將犧牲因為assertion而引起一部分性能損失。Java專家小組認為,所犧牲的性能相當小,因此java采用了運行時決定方式。
另外,我們注意到AssertionError作為Error的一個子類,而不是RuntimeException。關于這一點,專家組也進行了長期的討論。Error代表一些異常的錯誤,通常是不可以恢復的,而RuntimeException強調該錯誤在運行時才發生的特點。AssertionError通常為非常關鍵的錯誤,這些錯誤往往是不容易恢復的,而且assertion機制也不鼓勵程序員對這種錯誤進行恢復。因此,為了強調assertion的含義,Java專家小組選擇了讓AssertError為Error的子類。
§1.1.3 assertion 與繼承
在本節,我們將考慮assertion與繼承的關系,研究assert是如何定位的。如果開啟一個子類的assertion,那么它的父類的assertion是否執行?
下面的例子將顯示如果一個assert語句在父類,而當它的子類調用它時,該assert為false。我們看看在不同的情況下,該assertion是否被處理。
class Base
{
}
class Derived
{
}
運行命令 |
含義 |
結果 |
Java Derived |
不啟用assertion |
Base Method |
Java -ea Derived |
開啟所有assertion |
Java.lang.AssertionError:Assertion Failed:This is base |
Java -da Derived |
關閉所有assertion |
Base Method |
Java -ea:Base Derived |
僅打開Base的assertion |
Java.lang.AssertionError:Assertion Failed:This is base |
Java -ea:Derived Derived |
僅打開Derived的assertion |
Base Method |
從這個例子我們可以看出,父類的assert語句將只有在父類的assert開啟才起作用,如果僅僅開啟子類的assert,父類的assert仍然不運行。例如,我們執行java -ea:Derived Derived的時候,Base類的assert語句并不執行。因此,我們可以認為,assert語句不具有繼承功能。
§1.1.4 assertion 的使用
assertion的使用是一個復雜的問題,因為這將涉及到程序的風格,assertion運用的目標,程序的性質等問題。通常來說,assertion用于檢查一些關鍵的值,并且這些值對整個程序,或者局部功能的完成有很大的影響,并且這種錯誤不容易恢復的。assertion表達式應該短小、易懂,如果需要評估復雜的表達式,應該使用函數計算。以下是一些使用assertion的情況的例子,這些方式可以讓java程序的可靠性更高。
1.
例如:x取值只能使1,2,3,我們的程序可以如下表示
2.
3.
4.
5.
6.
7.
8.
例如:某函數可能要求輸入的參數必須不為null。那么我們可以在函數的一開始加上 assert parameter1!=null : "paramerter is null in test method";
9.
例如,我們有一個計算絕對值的函數,那么我們就可以在函數的結果處,加上一個語句:
assert
通過這種方式,我們可以對函數計算完的結果進行檢查。
10.
例如,在一個財會系統中,公司的支出和收入必須保持一定的平衡關系,因此我們可以編寫一個表達式檢查這種平衡關系,如下表示。
11.
12.
13.
在這個系統中,在一些可能影響這種平衡關系的方法的前后,我們都可以加上assert驗證:assert isBalance():"balance is destoried";
§1.1.5 結論
assertion為開發人員提供了一種靈活地調試和測試機制,它的使用也非常簡單、方便。但是,如何規范、系統地使用assertion(特別是在Java語言中)仍然是一個亟待研究的問題
posted on 2009-10-16 11:38 李云澤 閱讀(349) 評論(0) 編輯 收藏 所屬分類: 面試筆試相關的 、SCJP認證學習