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

此時我們運行專案 發現拋出了例外
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 (啟用斷言)選項的情況下運行都不會產生輸出,當斷言未啟用時,它們不會執行,盡管它們仍然存在于類檔案中,
前置條件和后置條件
前置條件: 是在執行某些代碼之前必須求值為 true 的條件
后置條件: 是在執行某些代碼后必須求值為 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 <code>filespec</code> is
* <code>null</code>
*/
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 < x.length - 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 < x.length; 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關鍵字需要在運行時候顯式開啟才能生效,否則你的斷言就沒有任何意義,而現在主流的Java IDE工具默認都沒有開啟-ea斷言檢查功能,這就意味著你如果使用IDE工具編碼,除錯運行時候會有一定的麻煩,并且,對于Java Web應用,程式代碼都是部署在容器里面,你沒法直接去控制程式的運行,如果一定要開啟-ea的開關,則需要更改Web容器的運行配置引數,這對程式的移 植和部署都帶來很大的不便,
2、用assert代替if是陷阱之二,assert的判斷和if陳述句差不多,但兩者的作用有著本質的區別:assert關鍵字本意上是為測驗 除錯程式時使用的,但如果不小心用assert來控制了程式的業務流程,那在測驗除錯結束后去掉assert關鍵字就意味著修改了程式的正常的邏輯,
3、assert斷言失敗將面臨程式的退出,這在一個生產環境下的應用是絕不能容忍的,一般都是通過例外處理來解決程式中潛在的錯誤,但是使用斷言就很危險,一旦失敗系統就掛了,
總結
assert既然是為了除錯測驗程式用,不在正式生產環境下用,那應該考慮更好的測驗JUint來代替其做用,JUint相對assert關鍵的所提供的功能是有過之而無不及,當然完全可以通過IDE debug來進行除錯測驗
因此,應當避免在Java中使用assert關鍵字,除非哪一天Java默認支持開啟-ea的開關,這時候可以考慮,對比一下,assert能給你帶來多少好處,多少麻煩,這是我們選擇是否使用的的原則,讀者可以自行取舍.
完
關注公眾號:java寶典
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/249688.html
標籤:Java
上一篇:RabbitMQ作業模式詳解
下一篇:Java中多個占位標記的泛型類

