Private Function Velocity ( _
ByVal latitude As Single, _
ByVal longitude As Single, _
ByVal elevation As Single _
) As Single
'Preconditions
Debug.Assert(-90 <= latitude And latitude <= 90)
Debug.Assert(0 <= longitude And longitude < 360)
Debug.Assert(-500 <= elevation And elevation <= 75000)
'Postconditions
Debug.Assert( 0 <= returnVelocity And returnVelocity <=
600 )
'return value
Velocity = returnVelocity
End Function
对于高健壮性的代码,应该先使用断言再处理错误
Private Function Velocity ( _
) As Single
' Preconditions
Debug.Assert(-90 <= latitude And latitude <= 90)
Debug.Assert(0 <= longitude And longitude < 360)
Debug.Assert(-500 <= elevation And elevation <= 75000)
If (latitude < -90) Then
latitude = -90
ElseIf (latitude > 90) Then
latitude = 90
End If
If (longitude < 0) Then
longitude = 0
ElseIf (longitude > 360) Then ...
2.4.7. 前置条件
不要断言方法的规范
/**
* Sets the refresh rate.
* @param rate refresh rate, in frames per second.
* @throws IllegalArgumentException if rate <= 0 or
* rate > MAX_REFRESH_RATE.
*/publicvoidsetRefreshRate(int rate){// Enforce specified precondition in public methodif(rate <=0|| rate > MAX_REFRESH_RATE)thrownewIllegalArgumentException("Illegal rate: "+ rate);setRefreshInterval(1000/rate);}
可以断言非public方法的前置条件
/**
* Sets the refresh interval (to a legal frame rate).
* @param interval refresh interval in milliseconds.
*/privatevoidsetRefreshInterval(int interval ){// preconditions in nonpublic methodassert interval >0&& interval <=1000/MAX_REFRESH_RATE : interval;...// Set the refresh interval}
2.4.8. 不变式Invariants
永远都应该为真的条件
内部不变式
程序运行到特定时刻应该为真的事实
如:assert x > 0
控制流不变式
断言不会被运行到的代码,如assert false: suit;
注意:将语句放置在编译器认为不会被运行到的地方会报错
类不变式
指类对象作为有效的类成员必须满足的条件
如:assert person.age >= 0 && person.age < 150;
在即将从public方法和构造函数中返回时断言类的不变式
2.4.9. 注意
断言是提高软件质量技术的有益辅助手段
可看作是可执行的注解
相比注释,能更主动地对程序中的假定作出说明
不能依赖断言来让代码正常工作:最佳方式是在一开始不要在代码中引入错误
断言不能有任何副作用
int i=pullNumberFromThinAir();assert(i =6);//错误的断言导致i被赋值printf("i is 8d\n",i);
2.4.10. Question: 应该进行多少约束校验?
每一行都设置一个校验?过多的约束校验,可能使得代码的逻辑变得不明确
可读性是衡量程序质量的最佳标准
在主要函数中放置前置条件和后置条件,并且在关键的循环中放置不变条件,就已经足够了
在修正错误的地方加入一条断言也是一个良好的习惯
2.4.11. 补充:断言举例
publicclassAssertionDemo{publicstaticvoidmain(String[] args){int i;int sum =0;for(i =0; i <10; i++){
sum += i;}assert i ==10;assert sum >10&& sum <5*10:"sum is "+ sum;}}
try{
statement1;//Suppose no exceptions in the statements
statement2;//Suppose an exception of type Exception1 is thrown in statement2
statement3;}catch(Exception1 ex){
handling ex;// The exception is handled.}catch(Exception2 ex){
handling ex;// Handling exception throw ex;// Rethrow the exception and control is transferred to the caller}finally{
finalStatements;// The final block is always executed}Next statement;// Next statement in the method is executed
try{// lots of code}catch(AnException exception ){LogError("Unexpected exception");}
3.5.6. 使用建议(补)
了解所用函数库可能抛出的异常
未能捕获由函数库抛出的异常可导致程序崩溃
可通过编写原型代码来演练该函数库
把项目中对异常的使用标准化
当抛出多种类型的异常,如对象、数据及指针的话,则考虑建立一个标准
创建项目的特定异常类:构造自己的异常类继承体系
规定哪些异常在局部处理,哪些不在局部处理
规定是否可以在构造或析构函数处理异常
确定是否要使用集中的异常报告机制
3.5.7. Exception Classes
3.5.7.1. System Errors
3.5.7.2. Exceptions
3.5.7.3. Runtime Exceptions
考虑创建一个集中的异常报告机制
Visual Basic示例:集中的异常报告机制(定义部分)
Sub ReportException( _
ByVal className , _
ByVal thisException As Exception _
)
Dim message As String
Dim caption As String
message =
"Exception: " & thisException .Message &
"Class : " & className & ControlChars .CrLf &
"Routine: " & thisException . TargetSite . Narne & ControlChars .CrLf
caption = "Exception"
MessageBox . Show( message , caption , MessageBoxButtons . OK, _
MessageBoxlcon . Exclarmation )
End Sub
集中的异常报告机制
Visual Basic示例: 集中的异常报告机制(调用部分)
Try
…
Catch exceptionObject As Exception
ReportException( CLASS_NAME , exceptionObject )
End Try
此处的异常报告只是一个非常简单的情况,实际开发中可以根据异常处理的需要开发或简或繁的代码
3.5.8. 使用建议(补)
考虑异常的替换方案
不要因为编程语言提供了异常而使用它:“深入一种语言去编程”
应自始至终考虑各种各样的错误处理机制
思考,是否真的需要处理异常
try{System.out.println(refVar.toString());}catch(NullPointerException ex){System.out.println("refVar is null");if(refVar !=null)System.out.println(refVar.toString());elseSystem.out.println("refVar is null");