assert(編程術語)

assert(編程術語)

編寫代碼時,咱們老是會作出一些假設,斷言就是用於在代碼中捕捉這些假設,能夠將斷言看做是 異常處理的一種高級形式。斷言表示爲一些 布爾表達式,程序員相信在程序中的某個特定點該表達式值爲真。能夠在任什麼時候候啓用和禁用斷言驗證,所以能夠在測試時啓用斷言,而在部署時禁用斷言。一樣,程序投入運行後,最終用戶在遇到問題時能夠從新起用斷言。
中文名
assert
前置條件斷言
代碼執行以前必須具有的特性
解    釋
維護,堅持;主張擁有等
注    意
assert是宏,而不是函數
使用斷言能夠建立更穩定,品質更好且不易於出錯的代碼。當須要在一個值爲FALSE時中斷當前操做的話,可使用斷言。 單元測試必須使用斷言(Junit/JunitX)。
除了類型檢查和單元測試外,斷言還提供了一種肯定各類特性是否在程序中獲得維護的極好的方法。
使用斷言使咱們向按契約式設計更近了一步。

斷言特性

編輯
前置條件斷言:代碼執行以前必須具有的特性
後置條件斷言:代碼執行以後必須具有的特性
先後不變斷言:代碼執行先後不能變化的特性

使用方式

編輯
斷言能夠有兩種形式
1.assert Expression1
2.assert Expression1:Expression2
其中Expression1應該老是一個布爾值,Expression2 是斷言失敗時輸出的失敗消息的字符串。若是Expression1爲假,則拋出一個 AssertionError,這是一個錯誤,而不是一個異常,也就是說是一個不可控制異常(unchecked Exception),AssertionError因爲是錯誤,因此能夠不捕獲,但不推薦這樣作,由於那樣會使你的系統進入不穩定狀態。

java斷言

編輯
斷言在默認狀況下是關閉的,要在編譯時啓用斷言,須要使用source1.4標記 即javac source1.4 Test.java ,在運行時啓用斷言須要使用 -ea參數 。要在系統類中啓用和禁用斷言可使用 -ea和 -dsa參數。
例如:
1
2
3
4
5
6
7
8
9
public  class  AssertExampleOne{
     public  AssertExampleOne(){}
     public  static  void  main(String args[]){
         int  x= 10 ;
         System.out.println( "Testing Assertion that x==100" );
         assert  x== 100 : "Out assertion failed!" ;
         System.out.println( "Test passed!" );
     }
}
若是編譯時未加 -source1.4,則編譯通不過
在執行時未加 -ea 時輸出爲
Testing Assertion that x==100
Test passed!
jre忽略了斷言的舊代碼,而使用了該參數就會輸出爲
Testing Assertion that x==100
Exception in thread "main" java.lang.AssertionError: Out assertion failed!
at AssertExampleOne.main(AssertExampleOne.java:6)
斷言的反作用
因爲程序員的問題,斷言的使用可能會帶來反作用 ,例如:
boolean isEnable=false;
//...
  assert isEnable=true;
這個斷言的反作用是由於它修改了程序中變量的值而且未拋出錯誤,這樣的錯誤若是不細心的檢查是很難發現的。可是同時咱們能夠根據以上的反作用獲得一個有用的特性,根據它來測試斷言是否打開。
1
2
3
4
5
6
7
8
9
10
public  class  AssertExampleTwo{
     public  static  void  main(String args[]){
         boolean  isEnable= false ;
         //...
         assert  isEnable= true ;
         if (isEnable== false ){
             throw  newRuntimeException( "Assertion should be enable!" );
         }
     }
}

使用斷言

編輯
1.能夠在預計正常狀況下程序不會到達的地方放置斷言 :assert false
2.斷言能夠用於檢查傳遞給私有方法的參數。(對於公有方法,由於是提供給外部的接口,因此必須在方法中有相應的參數檢驗才能保證代碼的健壯性)
3.使用斷言測試方法執行的前置條件和後置條件
4.使用斷言檢查類的不變狀態,確保任何狀況下,某個變量的狀態必須知足。(如age屬性應大於0小於某個合適值)
不用斷言
斷言語句不是永遠會執行,能夠屏蔽也能夠啓用
所以:
1.不要使用斷言做爲公共方法的參數檢查,公共方法的參數永遠都要執行
2.斷言語句不能夠有任何邊界效應,不要使用斷言語句去修改變量和改變方法的返回值.
C裏的宏
宏名: assert
功 能: 測試一個條件並可能使程序終止
用 法: void assert(int test);
程序例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<assert.h>
#include<stdio.h>
#include<stdlib.h>
struct  ITEM
{
     int  key;
     int  value;
};
/*add item to list,make sure list is not null*/
void  additem( struct  ITEM* itemptr)
{
     assert (itemptr!=NULL);
     /*additemtolist*/
}
int  main( void )
{
     additem(NULL);
     return  0;
}
assert() 宏用法
注意:assert是宏,而不是函數。在C的 assert.h頭文件中。
assert宏的原型定義在<assert.h>中,其做用是若是它的條件返回錯誤,則終止程序執行,原型定義:
1
2
3
4
5
6
#defineassert(expr)\
((expr)\
?__ASSERT_VOID_CAST(0)\
:__assert_fail(__STRING(expr),__FILE__,__LINE__,__ASSERT_FUNCTION))
 
/*DefinedInGlibc2.15*/
assert的做用是先計算表達式 expr, 若是其值爲假(即爲0),那麼它會打印出來assert的內容和__FILE__, __LINE__, __ASSERT_FUNCTION,而後執行abort()函數使kernel殺掉本身並coredump(是否生成coredump文件,取決於系統 配置);不然,assert()無任何做用。宏assert()通常用於確認程序的正常操做,其中表達式構造無錯時才爲真值。完成調試後,沒必要從源代碼中 刪除assert()語句,由於宏NDEBUG有定義時,宏assert()的定義爲空。 [1]  
請看下面的程序清單badptr.c:
1
2
3
4
5
6
7
8
9
10
11
12
13
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
int  main( void ){
     FILE * fp;
     fp= fopen ( "test.txt" , "w" ); //以可寫的方式打開一個文件,若是不存在就建立一個同名文件
     assert (fp); //因此這裏不會出錯
     fclose (fp);
     fp= fopen ( "noexitfile.txt" , "r" ); //以只讀的方式打開一個文件,若是不存在就打開文件失敗
     assert (fp); //因此這裏出錯
     fclose (fp); //程序永遠都執行不到這裏來
     return  0;
}
[root@localhost error_process]# gcc badptr.c
[root@localhost error_process]# ./a.out
a.out: badptr.c:14: main: Assertion `fp' failed.
若是使用動態連接libc,那麼除了__FILE__, __LINE__, __ASSERT_FUNCTION會讓目標變的稍稍大了一點,並不會由於屢次使用assert()增長目標不少。不過好處也很明顯,就是會在 assert的地方會打印出來文件名,行數,和函數名。另外,要注意用assert()的錯誤程度。若是assert()的條件fail了,那麼會調用 abort()函數讓kernel殺掉本身,哪怕用戶本身從新註冊了SIGABRT信號的行爲(abort()會先向本身發送信號SIGABRT保證用戶 的handler正確執行,而後修改SIGABRT信號的行爲爲默認行爲coredump,再次像本身發送SIGABRT,coredump)。
在調試結束後,能夠經過在包含#include <assert.h>的語句以前插入 #define NDEBUG 來禁用assert調用,示例代碼以下:
#include <stdio.h>
#define NDEBUG
#include <assert.h>
用法總結與注意事項:
1)在函數開始處檢驗傳入參數的合法性
如:
int resetBufferSize(int nNewSize){ //功能:改變緩衝區大小, //參數:nNewSize緩衝區新長度 //返回值:緩衝區當前長度 //說明:保持原信息內容不變 nNewSize<=0表示清除緩衝區 assert(nNewSize >= 0); assert(nNewSize <= MAX_BUFFER_SIZE); ...}
2)每一個assert只檢驗一個條件,由於同時檢驗多個條件時,若是斷言失敗,沒法直觀的判斷是哪一個條件失敗
/***很差***/assert(nOffset>=0 && nOffset+nSize<=m_nInfomationSize);/****好****/assert(nOffset >= 0);assert(nOffset+nSize <= m_nInfomationSize);
3)不能使用改變環境的語句,由於assert只在DEBUG生效,若是這麼作,會使用程序在真正運行時遇到問題
錯誤: assert(i++ < 100)
這是由於若是出錯,好比在執行以前i=100,那麼這條語句就不會執行,那麼i++這條命令就沒有執行。
正確: assert(i < 100)
i++;
4)assert和後面的語句應空一行,以造成邏輯和視覺上的一致感
5)有的地方,assert不能代替條件過濾
注意:當對於浮點數:
#include<assert.h>
float pi=3.14f;
assert (pi==3.14f);
在switch語句中老是要有default子句來顯示信息(Assert)。
int number = SomeMethod();
switch(number){
case 1: Trace.WriteLine("Case 1:");
break;
case 2: Trace.WriteLine("Case 2:");
break;
default : Debug.Assert(false);
break;
}
相關文章
相關標籤/搜索