如何在 Java 中使用斷言
如何在 Java 中使用斷言
什么是 Java 斷言?
在 JDK 1.4之前,開發(fā)人員經常使用注釋來記錄關于程序正確性的假設。然而,注釋作為測試和調試假設的機制是無用的。編譯器忽略注釋,因此無法使用它們進行 bug 檢測。開發(fā)人員在更改代碼時也經常不更新注釋。
在 JDK 1.4中,斷言被引入作為測試和調試代碼假設的新機制。實質上,斷言是在運行時執(zhí)行的可編譯實體,假設你已經為程序測試啟用了它們。可以通過編寫斷言來通知 bug 發(fā)生的地方,這樣可以大大減少調試失敗程序的時間。
如何用 Java 編寫斷言
編寫斷言的表達式:
assert?BooleanExpr;
如果 BooleanExpr 的計算結果為 true,則不會發(fā)生任何事情,并繼續(xù)執(zhí)行。但是,如果表達式計算結果為 false,那么將拋出 AssertionError
舉個例子
????public?static?void?main(String[]?args)?{
????????int?a?=?10;
????????assert?a>100;//false
????}
此斷言表明開發(fā)人員認為變量 a 包含一個大于100的值。但是,情況顯然不是這樣;
assert 語句的執(zhí)行導致拋出 AssertionError
運行后沒有反應??
有的小伙伴發(fā)現(xiàn)自己的IDE并沒有拋出Error 這是因為沒有顯示開啟,啟用斷言開啟方法: vm options 加入 -ea

此時我們運行項目 發(fā)現(xiàn)拋出了異常
Exception?in?thread?"main"?java.lang.AssertionError
?at?Scratch.main(scratch_4.java:4)
希望獲得更多信息?
此時我們已經知道了斷言的基本用法 但是拋出Error后我們并不知道是什么問題導致的 還需要去翻看代碼找到報錯的地方, 如果我們希望獲得更多有用的信息 我們可以這樣修改Assert語句:
assert?BooleanExpr?:?expr;
expr 是任何可以返回值的表達式(包括方法調用)但是不能調用具有 void 返回類型的方法。一個有用的表達式是一個字符串,用它來描述失敗的原因
舉個例子
public?static?void?main(String[]?args)?{
????????int?a?=?10;
????????assert?a>100?:?"a?100";?
????}
運行:
Exception?in?thread?"main"?java.lang.AssertionError:?a?100
?at?Scratch.main(scratch_4.java:5)
無論哪個例子,在不使用-ea (啟用斷言)選項的情況下運行都不會產生輸出。當斷言未啟用時,它們不會執(zhí)行,盡管它們仍然存在于類文件中。
前置條件和后置條件
前置條件: 是在執(zhí)行某些代碼之前必須求值為 true 的條件
后置條件: 是在執(zhí)行某些代碼后必須求值為 true 的條件
前置條件
前置條件檢查:
import?java.io.FileInputStream;
import?java.io.IOException;
import?java.io.InputStream;
class?PNG
????{
????????/**
?????????*??Create?a?PNG?instance,?read?specified?PNG?file,?and?decode
?????????*??it?into?suitable?structures.
?????????*
?????????*??@param?filespec?path?and?name?of?PNG?file?to?read
?????????*
?????????*??@throws?NullPointerException?when?filespec?is
?????????*??????????null
?????????*/
????????PNG(String?filespec)?throws?IOException
????????{
????????????//在非私有構造方法中?使用前置條件
????????????if?(filespec?==?null)
????????????????throw?new?NullPointerException("filespec?is?null");
????????????try?(FileInputStream?fis?=?new?FileInputStream(filespec))
????????????{
????????????????readHeader(fis);
????????????}
????????}
????????private?void?readHeader(InputStream?is)?throws?IOException
????????{??
????????????????//在私有方法中使用前置條件檢查
????????????assert?is?!=?null?:?"null?passed?to?is";
????????}
????}
????class?Scratch
????{
????????public?static?void?main(String[]?args)?throws?IOException
????????{
????????????PNG?png?=?new?PNG((args.length?==?0)???null?:?args[0]);
????????}
????}
后置條件
后置條件檢查:
public?class?AssertDemo
{
???public?static?void?main(String[]?args)
???{
??????int[]?array?=?{?20,?91,?-6,?16,?0,?7,?51,?42,?3,?1?};
??????sort(array);
??????for?(int?element:?array)
?????????System.out.printf("%d?",?element);
??????System.out.println();
???}
???private?static?boolean?isSorted(int[]?x)
???{
??????for?(int?i?=?0;?i?1;?i++)
?????????if?(x[i]?>?x[i?+?1])
????????????return?false;
??????return?true;
???}
???private?static?void?sort(int[]?x)
???{
??????int?j,?a;
??????//?For?all?integer?values?except?the?leftmost?value?...
??????for?(int?i?=?1;?i???????{
?????????//?Get?integer?value?a.
?????????a?=?x[i];
?????????//?Get?index?of?a.?This?is?the?initial?insert?position,?which?is
?????????//?used?if?a?is?larger?than?all?values?in?the?sorted?section.
?????????j?=?i;
?????????//?While?values?exist?to?the?left?of?a's?insert?position?and?the
?????????//?value?immediately?to?the?left?of?that?insert?position?is
?????????//?numerically?greater?than?a's?value?...
?????????while?(j?>?0?&&?x[j?-?1]?>?a)
?????????{
????????????//?Shift?left?value?--?x[j?-?1]?--?one?position?to?its?right?--
????????????//?x[j].
????????????x[j]?=?x[j?-?1];
????????????//?Update?insert?position?to?shifted?value's?original?position
????????????//?(one?position?to?the?left).
????????????j--;
?????????}
?????????//?Insert?a?at?insert?position?(which?is?either?the?initial?insert
?????????//?position?or?the?final?insert?position),?where?a?is?greater?than
?????????//?or?equal?to?all?values?to?its?left.
?????????x[j]?=?a;
??????}
??????//在 sort ()返回給它的調用者之前,我使用 assert 檢查 x 被排序的后置條件。
??????assert?isSorted(x):?"array?not?sorted";
???}
}
陷阱
assert關鍵字用法簡單,但是使用assert往往會讓你陷入越來越深的陷阱中。應避免使用。筆者經過研究,總結了以下原因:
★1、 assert關鍵字需要在運行時候顯式開啟才能生效,否則你的斷言就沒有任何意義。而現(xiàn)在主流的Java IDE工具默認都沒有開啟-ea斷言檢查功能。這就意味著你如果使用IDE工具編碼,調試運行時候會有一定的麻煩。并且,對于Java Web應用,程序代碼都是部署在容器里面,你沒法直接去控制程序的運行,如果一定要開啟-ea的開關,則需要更改Web容器的運行配置參數(shù)。這對程序的移 植和部署都帶來很大的不便。
”
★2、用assert代替if是陷阱之二。assert的判斷和if語句差不多,但兩者的作用有著本質的區(qū)別:assert關鍵字本意上是為測試 調試程序時使用的,但如果不小心用assert來控制了程序的業(yè)務流程,那在測試調試結束后去掉assert關鍵字就意味著修改了程序的正常的邏輯。
”
★3、assert斷言失敗將面臨程序的退出。這在一個生產環(huán)境下的應用是絕不能容忍的。一般都是通過異常處理來解決程序中潛在的錯誤。但是使用斷言就很危險,一旦失敗系統(tǒng)就掛了。
”
總結
assert既然是為了調試測試程序用,不在正式生產環(huán)境下用,那應該考慮更好的測試JUint來代替其做用,JUint相對assert關鍵的所提供的功能是有過之而無不及。當然完全可以通過IDE debug來進行調試測試
因此,應當避免在Java中使用assert關鍵字,除非哪一天Java默認支持開啟-ea的開關,這時候可以考慮。對比一下,assert能給你帶來多少好處,多少麻煩,這是我們選擇是否使用的的原則,讀者可以自行取舍.
完 小伙伴記得點贊 關注!!

今天我們主要分析Thread Dump

學習單例模式引發(fā)的思考

JVM生成的這3種文件,你都見過嗎?

一文搞懂什么是事務
