文章目錄
斷言(Assertion)是一種調試程式的方式。在Java中,使用assert關鍵字來實作斷言。
假設确信某個屬性符合要求, 并且代碼的執行依賴于這個屬性。例如, 需要計算:
double y = Math.sqrt(x);
确信,這裡的 X 是一個非負數值。原因是:X 是另外一個計算的結果,而這個結果不可能是負值;或者 X 是一個方法的參數,而這個方法要求它的調用者隻能提供一個正整數。
當然還應當進行檢查, 以避免讓“ 不是一個數” 的數值參與計算操作。
可以抛出一個異常:
if (x < 0) throw new 111egalArgumentException("x < 0");
但是這段代碼會一直保留在程式中, 即使測試完畢也不會自動地删除。如果在程式中含有大量的這種檢查,程式運作起來會相當慢。
斷言機制允許在測試期間向代碼中插入一些檢査語句。當代碼釋出時,這些插人的檢測語句将會被自動地移走。
Java 語言引人了關鍵字 assert。這個關鍵字有兩種形式:
assert 條件;
assert 條件:表達式;
這兩種形式都會對條件進行檢測, 如果結果為 false, 則抛出一個 AssertionError 異常。
在第二種形式中,表達式将被傳人 AssertionError 的構造器, 并轉換成一個消息字元串。
在預設情況下, 斷言被禁用。可以在運作程式時用 -enableassertions 或 -ea 選項啟用:
java -enableassertions MyApp
需要注意的是, 在啟用或禁用斷言時不必重新編譯程式。啟用或禁用斷言是類加載器( class loader) 的功能。當斷言被禁用時, 類加載器将跳過斷言代碼, 是以,不會降低程式運作的速度。
也可以在某個類或整個包中使用斷言, 例如:
java -ea:MyClass -eaiconi.inycompany.inylib.. , MyApp
這條指令将開啟 MyClass 類以及在 com.mycompany.mylib 包和它的子包中的所有類的斷言。選項 -ea 将開啟預設包中的所有類的斷言。
也可以用選項 -disableassertions 或 -da 禁用某個特定類和包的斷言:
ava -ea:... -da:MyClass MyApp
每個 Java 程式員都很熟悉在有問題的代碼中插入一些 System.out.println 方法調用來幫助觀察程式運作的操作過程。 當然, 一旦發現問題的根源, 就要将這些語句從代碼中删去。如果接下來又出現了問題, 就需要再插入幾個調用 System.out.println方法的語句。
記錄日志API 就是為了解決這個問題而設計的。
下面先讨論這些 API 的優點。
- 可以很容易地取消全部日志記錄,或者僅僅取消某個級别的日志,而且打開和關閉這個操作也很容易。
- 可以很簡單地禁止日志記錄的輸出, 是以,将這些日志代碼留在程式中的開銷很小。
- 日志記錄可以被定向到不同的處理器, 用于在控制台中顯示, 用于存儲在檔案中等。
- 日志記錄器和處理器都可以對記錄進行過濾。過濾器可以根據過濾實作器制定的标準丢棄那些無用的記錄項。
- 日志記錄可以采用不同的方式格式化,例如,純文字或 XML。
-
應用程式可以使用多個日志記錄器, 它們使用類似包名的這種具有層次結構的名字,例如, com.mycompany.myapp0 •在預設情況下,日志系統的配置由配置檔案控制。如果需要的話, 應用程式可以替換
這個配置。
要生成簡單的日志記錄,可以使用全局日志記錄器(global logger) 并調用其 info 方法:
Logger.getClobal 0,info("File->Open menu item selected");
在預設情況下,這條記錄将會顯示以下内容:
May 10, 2013 10:12:15 PM LogginglmageViewer fileOpen
INFO: File->0pen menu item selected
但是, 如果在适當的地方(如 main 開始)調用
Logger.getClobal ().setLevel (Level .OFF);
将會取消所有的日志。
API: java.util.logging
從前面已經看到“ 虛拟日志”,下面繼續看一下企業級( industrial-strength) 日志。在一個專業的應用程式中,不要将所有的日志都記錄到一個全局日志記錄器中,而是可以自定義日志記錄器。
可以調用 getLogger 方法建立或擷取記錄器:
private static final Logger myLogger = Logger.getLogger("com.mycompany.myapp"):
與包名類似,日志記錄器名也具有層次結構。事實上, 與包名相比,日志記錄器的層次性更強。 對于包來說,一個包的名字與其父包的名字之間沒有語義關系,但是日志記錄器的父與子之間将共享某些屬性。例如, 如果對 com.mycompany 日志記錄器設定了日志級别,它的子記錄器也會繼承這個級别 。
通常, 有以下 7 個日志記錄器級别:
- SEVERE
- WARNING
- INFO
- CONFIG
- FINE
- FINER
- FINEST
在預設情況下,隻記錄前夂個級别。 也可以設定其他的級別。例如:
logger,setLevel (Level .FINE);
現在, FINE 和更進階别的記錄都可以記錄下來。
另外, 還可以使用 Level.ALL 開啟所有級别的記錄, 或者使用 Level.OFF 關閉所有級别的記錄。
對于所有的級别有下面幾種記錄方法:
logger.warning(message):
logger,fine(message) ;
同時, 還可以使用 log 方法指定級别, 例如:
logger.log(Level .FINE, message);
日志記錄常用的操作:
- 1 ) 為一個簡單的應用程式, 選擇一個日志記錄器,并把日志記錄器命名為與主應用程式包一樣的名字,例如,com.mycompany.myprog。
可以通過調用下列方法得到日志記錄器:
Logger logger = Logger.getLogger("com.mycompany.myprog");
為了友善,可以利用一些日志操作将下面的靜态域添加到類中:
private static final Logger logger = Logger.getLogger("com.mycompany.nyprog"):
- 2 ) 預設的日志配置将級别等于或高于 INFO 級别的所有消息記錄到控制台。使用者可以覆寫預設的配置檔案。但是正如前面所述,改變配置需要做相當多的工作。是以,最好在應用程式中安裝一個更加适宜的預設配置。
下列代碼確定将所有的消息記錄到應用程式特定的檔案中。可以将這段代碼放置在應用程式的 main方法中。
if (System,getProperty("java,util.logging.config.dass") == null
&& System.getPropertyC'java.util.logging.config.file") == null) {
try
{
Logger.getLogger("").setLevel(Level.ALL);
final int L0C_R0TATI0N_C0UNT = 10;
Handler handler = new FileHandler('Wmyapp.log", 0, L0G_R0TATI0N_C0UNT):
Logger.getLogger("").addHandler(handler): }
catch (IOException e) {
logger.log(Level.SEVERE, "Can't create log file handler", e);
}
}
- 3 ) 現在,可以記錄自己想要的内容了。但需要注意:所有級别為 INFO、 WARNING 和SEVERE 的消息都将顯示到控制台上。是以, 最好隻将對程式使用者有意義的消息設定為這幾個級别。将程式員想要的日志記錄,設定為 FINE 是一個很好的選擇。
當調用 System.out.println 時, 實際上生成了下面的日志消息:
logger.fine("File open dialog canceled";
記錄那些不可預料的異常也,例如:
try
{}
catch (SonreException e) {
logger,log(Level.FINE, "explanation", e);
}
在Intellij IDEA中使用Debug how2j.java:如何在Eclipse中調試Java程式 W3Cschool:jUnit教程 Spring Boot幹貨系列:(十二)Spring Boot使用單元測試
參考:
【1】:《Java核心技術 卷一》
【2】:
廖雪峰的官方網站:使用斷言【3】:
廖雪峰的官方網站:使用JDK Logging【4】:
廖雪峰的官方網站:使用Commons Logging【5】:
廖雪峰的官方網站:使用Log4j【6】:
廖雪峰的官方網站:使用SLF4J和Logback【7】:
how2j.java: Log4j系列教材