如何在 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能給你帶來多少好處,多少麻煩,這是我們選擇是否使用的的原則,讀者可以自行取捨.
完