愉快地學Java語言:第十五章 斷言與日誌

導讀

本文適合Java入門,不太適合Java中高級軟件工程師。本文以《Java核心技術基礎知識卷I》第10版為藍本,採用不斷提出問題,然後解答問題的方式來講述。本篇文章只是這個系列中的一篇,如果你喜歡這種講解方式,或者覺得從中能學到知識,可以關注我,以便查閱本系列其他文章。

讓我們開始愉快地學習Java語言吧!

愉快地學Java語言:第十五章 斷言與日誌

1斷言

為啥使用斷言?

斷言使程序具有自我保護能力!

我們在開發和測試階段,會加入一些檢測代碼輔助調試,這些代碼會隨其他代碼一起發佈,這樣勢必對性能有影響。斷言機制允許在測試期間向代碼中插入一些檢査語句。當代碼發佈時,這些插人的檢測語句將會被自動地移走。這樣正式發佈時,程序不會因為有大量的檢查語句而影響性能。

斷言只用於開發和測階段,確定程序內部的錯誤位置。

斷言的兩種形式

1)assert 條件;

2)assert 條件:表達式;

斷言執行的時候,對條件進行檢測,如果條件結構為false, 則拋出一個 AssertionError異常。

第二種形式與第一種的區別就是:表達式被傳入AssertionError的構造器並轉換成一個消息字符串。使用這個表達式的目的只有一個:產生一個消息字符串。所以一定不要使用這個表達式向客戶端傳遞任何跟業務相關的信息。

啟用與禁用斷言

那麼是誰控制斷言的啟用與禁用呢?

這是類加載器的職責。所以啟用或禁用斷言時不必重新編譯程序。

當斷言被禁用時,類加載器將跳過斷言代碼。

如何啟用斷言呢?

在默認情況下, 斷言被禁用,那麼我們要像下面這樣設置才能啟用斷言。

1)對於由類加載器加載的類而言:

用 -enableassertions 或 -ea 選項啟用。

例:java -enableassertions MyApp

也可以在某個類或整個包中使用斷言:

java -ea:MyClass -ea iconi.inycompany.inylib... MyApp

2)不是由類加載器加載,而是直接由虛擬機加載的類:

使用 -enablesystemassertions/-esa 開關啟用斷言

如何禁用斷言呢?

1)對於由類加載器加載的類而言:

使用-da禁用斷言

2)不是由類加載器加載,而是直接由虛擬機加載的類:

使用-dsa禁用斷言

2日誌

Java API提供的日誌記錄器

為什麼要記錄日誌呢?

當你開發程序時,會在有問題的代碼中插入System.out.println方法,以便打印執行的結果,好助你找到發生錯誤的位置。但是在發佈時,一定要刪除這些“無用”的代碼,這樣做太麻煩了,因此我們找到了更好的辦法,那就是記錄日誌。至此我們有了三大武器:異常、斷言、日誌,使程序具有自我保護能力,同時也方便我們調試代碼。

Java API提供了相應類:java.util.logging.Logger。本文簡單介紹下這個類的使用,因為在日常的開發中,我們使用最多的還是其他日誌組件,譬如SLF4J,log4j。

獲取日誌記錄器

private static final Logger logger= Logger.getLogger (“LoggerName”);

LoggerName:每個日誌記錄器都有一個名字

為什麼要將logger聲明為靜態變量呢?

因為未被任何變量引用的日誌記錄器可能會被垃圾回收,所以用一個靜態變量存儲日誌記錄器的一個引用。

日誌記錄器的級別

日誌記錄器有七個級別,從高到低依次為:SEVERE、WARNING、INFO、CONFIG、FINE、FINER、FINEST。

設置日誌記錄器的級別有什麼用呢?

可以有選擇地輸出不同等級的記錄。默認情況下,只記錄前三個級別,可以使用Level.ALL開啟所有級別的記錄,使用Level.OFF關閉日誌。

修改日誌配置

一般日誌配置文件位於jre/lib/1ogging.properties,可以配置java.util.logging.config.file特性,指定其他的位置。

java - Djava.util.logging.config.file=configFile MainClass。

3SLF4J

3.1 SLF4J使用模式

SLF4J是簡單日誌系統的Facade(門面),它為程序員提供了便利的方法,允許程序員在編寫代碼時不必考慮使用何種具體的日誌組件,而在部署程序時在考慮這些,下面是一般的使用模式。

愉快地學Java語言:第十五章 斷言與日誌

3.2 SLF4J概要

SLF4J只有一個強制依賴:slf4j-api,可以使用Maven管理依賴,例如使用1.7.25版本:

<dependency>

<groupid>org.slf4j/<groupid>

<artifactid>slf4j-api/<artifactid>

<version>1.7.25/<version>

從1.6.0版本開始,如果在類路徑下沒有找到綁定,那麼SLF4J將默認為無操作的實現。

從1.7.0版本開始,Logger接口提供了接收可變參數的打印方法,而不是如以前的接口那樣參數類型為Object[]。1.6.X版本中的由編譯器生成的Logger接口,1.7.X版本是無法理解的。1.7.X版本與1.6.X版本不兼容。

從1.7.5開始,顯著提高了記錄器檢索時間。鑑於改進的程度,強烈建議用戶遷移到1.7.5或更高版本。

從1.7.9版本開始,通過設置slf4j.detectLoggerNameMismatch這一系統屬性為true,SLF4J能自動地發現錯誤命名的Logger。

3.3 SLF4J綁定

SLF4J綁定是一種jar文件,它有多種類型。

我們運行上面的例子,運行結果如下:

愉快地學Java語言:第十五章 斷言與日誌

打印錯誤的原因是,在類路徑下沒有找到SLF4J綁定()。

如果你將slf4j-simple的依賴配置pom.xml中上述報錯就會消失。slf4j-simple是SLF4J的一個簡單實現。注意引入的版本要和slf4j-api匹配,例如slf4j-api我使用1.7.25版本,那麼slf4j-simple我也是使用1.7.25版本。

<dependency>

<groupid>org.slf4j/<groupid>

<artifactid>slf4j-simple/<artifactid>

<version>1.7.25/<version>

運行結果為:

愉快地學Java語言:第十五章 斷言與日誌

除了slf4j-simple這個綁定以外,還有幾種其他類型的綁定,每種綁定都對應著一種具體日誌組件。

1)slf4j-log4j12

這個綁定對應著log4j這個日誌組件。pom.xml配置如下:

<dependency>

<groupid>org.slf4j/<groupid>

<artifactid>slf4j-log4j12/<artifactid>

<version>1.7.21/<version>

<dependency>

<groupid>log4j/<groupid>

<artifactid>log4j/<artifactid>

<version>1.2.17/<version>

2)slf4j-jdk14

這個綁定對應java.util.logging,即JDK提供的日誌組件

3)slf4j-nop

這個綁定對應NOP,即no operation,默認地不記錄所有日誌。既然不記錄日誌,那麼我們引入它有什麼用呢?

如果不引入這個jar,那麼會像上面那樣輸出錯誤信息。

4)slf4j-jcl

這個綁定對應Apache Commons Logging,也被稱為 Jakarta Commons Logging。

5)logback-classic

這個綁定對應的是logback,近年來,好多公司由log4j轉向logback。Logback的ch.qos.logback.classic.Logger類直接實現了org.slf4j.Logger接口,因此,將SLF4J與logback結合使用會大量地減少內存和計算的開銷。

現在,想要切換日誌框架是一件非常簡單的事情,只要改變Maven的依賴配置就行。

切記,不能同時使用兩種日誌框架。

借用官網的一張圖,來說明它們的關係。

愉快地學Java語言:第十五章 斷言與日誌

3.4 SLF4J+log4j示例

下面以使用log4j為例,添加log4j後。運行後發現,報錯。

愉快地學Java語言:第十五章 斷言與日誌

這是沒有配置log4j的原因導致的。

那麼我們創建資源文件夾src/main/resource,在此文件夾下添加配置文件log4j.properties,並按如下配置:

愉快地學Java語言:第十五章 斷言與日誌

使用下列語句加載配置文件:

URL configURL = App.class.getClassLoader().getResource("log4j.properties");

PropertyConfigurator.configure(configURL);

運行結果如下:

愉快地學Java語言:第十五章 斷言與日誌

我們配置將info信息輸出到文件,可以看到確實有一個名為info的文件。

愉快地學Java語言:第十五章 斷言與日誌


分享到:


相關文章: