(給ImportNew加星標,提高Java技能)
編譯:ImportNew/唐尤華
itnext.io/lazy-logging-40314cf9bb25
在程式碼中新增日誌時要當心:有時儘管並沒有記錄日誌,也會執行日誌陳述句。
例如下麵的程式碼:
```java
log.debug("I found {} and {}", getone(), gettwo());
```
看起來很好,似乎沒有任何問題。日誌輸出字串中包含了兩個除錯引數。
所以一切正常,沒有問題?也不盡然。
在記錄日誌的程式碼中可以看到下麵兩個輸入:
- `getone()`
- `gettwo()`
這兩個方法會”一直“呼叫。這意味著,即使實際可能不會執行 `log` 陳述句,仍然會計算所有 `log` 方法傳入的引數。
如果這些呼叫開銷很大,那麼可能會浪費大量 CPU 資源。
一種典型的解決方案像下麵這樣:
```java
if (log.isDebugEnabled()) {
log.debug("I found {} and {}", getone(), gettwo());
}
```
但這種方法相當醜陋:這不正是 `log.debug` 完成的功能嗎?只在啟用除錯時才記錄日誌。
我們需要的是一個單行除錯陳述句,只在啟用日誌記錄時計算輸入的引數。
為瞭解決類似的情況,我們將應用 Java 8 Supplier 樣式,只在需要的時候執行計算。
不幸的是,大多數日誌框架並不支援 Supplier 樣式。
至少是直接支援。
實際上,`logger` 並不期望輸入的引數一定是字串,實際引數可以是任意物件。`logger` 會呼叫物件的 `toString` 方法把它轉換為字串。這裡的訣竅是`logger` 只在日誌啟用的情況下呼叫字串。
因此,要實現惰性日誌只需要用一個物件來包裝 Supplier,該物件僅在呼叫 toString 時呼叫 Supplier。
```java
import java.util.function.Supplier;
public class LazyString {
private final Supplier> stringSupplier;
public static LazyString lazy(Supplier> stringSupplier) {
return new LazyString(stringSupplier);
}
public LazyString(final Supplier> stringSupplier) {
this.stringSupplier = stringSupplier;
}
@Override
public String toString() {
return String.valueOf(stringSupplier.get());
}
}
```
現在可以更新之前的日誌程式碼,結果如下:
```java
import static LazyString.lazy;
log.debug("I found {} and {}", lazy(this::getone), lazy(this::gettwo));
```
理想情況下,日誌框架能直接支援 Supplier。但在等待的過程中,這也是一種變通的辦法。
完整示例程式碼,請檢視我的 Github 倉庫:
朋友會在“發現-看一看”看到你“在看”的內容