web-dev-qa-db-ja.com

ログインの遅延評価Java 8

計算にコストがかかる値よりも大きい値がある場合、ロギングフレームワークに見られる一般的なパターンは次のとおりです。

_if (log.isDebugEnabled()) {
    String value = expensiveComputation();
    log.debug("value: {}", value);
}
_

Java 8個のラムダが追加されたので、次のようにするとよいでしょう。

_log.debug("value: {}", (Supplier<String>) this::expensiveComputation);
_

ロギングフレームワークがパラメータに対してtoString()を実行するため、どちらがほぼ機能します。問題は、SuppliertoString()Objectの実装であるということです。

怠惰に評価されるものをLoggerメソッドに提供する方法はありますか? toString()を呼び出すデフォルトのget()を含むSupplierになります。

14
David Ehrmann

怠惰な方法で実行される引数をString計算に渡すには、SupplierではなくStringを渡す必要があります。
呼び出すメソッドには、次のシグネチャが必要です。

_void debug(Supplier<?> msgSupplier, Throwable t)
_

このユーティリティメソッドを独自のユーティリティクラスに導入できます。
ただし、Log4j2などの最近のロギングフレームワークがこの機能をすぐに提供するため、これを行う必要はありません

たとえば、 org.Apache.logging.log4j.Logger は、Supplierを受け入れるオーバーロードされたログメソッドを提供します。
の場合:

void debug(MessageSupplier msgSupplier, Throwable t)

パラメータとして渡されたThrowabletのスタックトレースを含むメッセージをログに記録します(ログレベルがDEBUGレベルの場合にのみ作成されます)。 MessageSupplierは、MessageFactoryを使用してメッセージを作成する場合と使用しない場合があります。

Parameters

msgSupplier-呼び出されると、目的のログメッセージを生成する関数。

t-スタックトレースを含むログの例外。

Log4j2ドキュメントから:

レイジーロギングのJava 8ラムダサポート

リリース2.4では、Loggerインターフェースでラムダ式のサポートが追加されました。これにより、クライアントコードは、要求されたログレベルが有効になっているかどうかを明示的に確認せずに、メッセージを遅延ログに記録できます。たとえば、以前は次のように記述します。

_if (logger.isTraceEnabled()) {
    logger.trace("Some long-running operation returned {}", expensiveOperation());
}
_

Java 8を使用すると、ラムダ式で同じ効果を得ることができます。ログレベルを明示的にチェックする必要はなくなりました。

_logger.trace("Some long-running operation returned {}", 
              () ->    expensiveOperation());
_
8
davidxxx

小さなヘルパーオブジェクトを使用すると、必要なことを実行できます。

public class MessageSupplier {
    private Supplier<?> supplier;

    public MessageSupplier(Supplier<?> supplier) {
        this.supplier = supplier;
    }

    @Override
    public String toString() {
        return supplier.get().toString();
    }

    public static MessageSupplier msg(Supplier<?> supplier) {
        return new MessageSupplier(supplier);
    }
}

次に、msgの静的インポートを使用します。

log.debug("foo: {}", msg(this::expensiveComputation));
5
teppic

ロギングフレームワークがパラメータに対してtoString()を実行するため、どちらがほぼ機能します。

このステートメントは正しくありません。 debug/info/whateverメソッドにステップインすると、次の実装が見つかります。

public void log(Level level, Supplier<String> msgSupplier) {
    if (!isLoggable(level)) {
        return;
    }
    LogRecord lr = new LogRecord(level, msgSupplier.get());
    doLog(lr);
}

levelが満たされない場合、Supplierは使用されません。

1
Mureinik

興味深いことに、このようなものを使用することさえできません

interface LazyString { String toString(); }

機能的なインターフェースとして

私がこれまでに見つけた唯一の方法は、匿名クラスを経由することです。

Object o = new Object() { @Override public String toString() { return myExpensiveComputation(); } }; System.out.printf("%s", o);

1

_Java.util.logging_およびJava 8+の場合、これを使用することもできますlazyおよび便利な表記:

_LOGGER.fine(() -> "Message1: "  + longComputation1() + ". Message2: " + longComputation2());
_

longComputation1()およびlongComputation2()は、レイジーと呼ばれます。つまり、必要な場合のみです。

0
adaslaw