ロガーslf4jには、文字列連結ではなく{}を使用してフォーマットする利点


100

{}文字列連結の代わりに使用する利点はありますか?

slf4jの例

logger.debug("Temperature set to {}. Old temperature was {}.", t, oldT);

の代わりに

logger.debug("Temperature set to"+ t + ". Old temperature was " + oldT);

構成ファイルによっては、実行時にパラメーターの評価(および文字列の連結)を回避できるため、速度の最適化が重要だと思います。ただし、使用できるパラメーターは2つだけであり、文字列の連結以外に選択肢がない場合があります。この問題についての意見が必要です。

回答:


74

これは、ある文字列連結パフォーマンスについて。高密度のロギングステートメントがある場合、それは潜在的に重要です。

(SLF4J 1.7より前)ただし、使用できるパラメーターは2つだけです

ロギングステートメントの大部分には2つ以下のパラメーターがあるため、バージョン1.6までのSLF4J APIは、大部分のユースケース(のみ)をカバーします。APIデザイナーは、APIバージョン1.7以降、varargsパラメーターを使用してオーバーロードされたメソッドを提供しています。

3つ以上のSLF4Jが必要な場合に2つ以上必要な場合は、文字列連結またはを使用してくださいnew Object[] { param1, param2, param3, ... }。パフォーマンスがそれほど重要ではないほど十分に少ないはずです。


2
未使用の文字列連結(つまり、デバッグ文)は避けてください。(過度に冗長ですが効率的な)ログレベルのチェックまたは(より細いが、おそらくわずかなオーバーヘッド)オブジェクト配列パラメーターのいずれかを使用してください。(私は後者を好み、すべてが同じです。)文字列連結が重要ではない/パフォーマンスに影響しないとは言いがたいです。オブジェクト配列の作成は、理論的にはインライン化されて最適化され、「実際には」違いをもたらさない可能性があります(希望的思考に対して)。(これは時期尚早の最適化ではなく、単に最初に正しい/より良いことを行うことの問題です。)
マイケル

System.out.println()がslf4jのロガーに似ているため、オーバーロードされた変更が行われず、文字列の連結が回避されるのはなぜですか?
a3.14_Infinity 2014年

44

ショートバージョン:はい、コードが少なくて済みます。

文字列の連結は、それが必要かどうかを知らずに多くの作業を行い(log4jから知られている従来の「デバッグが有効」なテスト)、{}によってtoString()呼び出しと文字列の作成を遅らせることができるため、可能であれば回避する必要があります。イベントのキャプチャが必要かどうかが決定された後。ロガーに単一の文字列をフォーマットさせることにより、コードはよりクリーンになると私は考えています。

引数はいくつでも指定できます。sljf4jの古いバージョンを使用していて、に3つ以上の引数が{}ある場合はnew Object[]{a,b,c,d}、代わりに構文を使用して配列を渡す必要があることに注意してください。たとえば、http : //slf4j.org/apidocs/org/slf4j/Logger.html#debug(java.lang.String、java.lang.Object [])を参照してください

速度に関して:Cekiはリストの1つにベンチマークをしばらく掲示しました。


6
注:最新のjavadocは、新しいvar-arg構文を示していますdebug(String format, Object... arguments)slf4j.org/faq.html#logging_performance
マイケル・

連結のパフォーマンスに加えて.toString()の評価について言及したため、賛成です。これはロガー内部で発生するものであり、ロガーはそのメソッドを呼び出す必要があるかどうかを判断できます。ログレベルバーが満たされていない場合は、そうではありません。
Chetan Narsude 2016年

6

StringはJavaでは不変であるため、連結のペアごとに、左側と右側のStringを新しいStringにコピーする必要があります。だから、プレースホルダーに行くほうがいい。


2
コンパイラが連結を文字列ビルダー呼び出しに変換するため、単一のペアがある場合はこれは正しいですが、一般的には正しくありません。
cdeszaq

3

別の選択肢はString.format()です。jcabi-logで使用しています(SLF4J周りの静的ユーティリティラッパー)。

Logger.debug(this, "some variable = %s", value);

それははるかに保守可能で拡張可能です。また、翻訳も簡単です。


3
私はそれがより保守可能だとは思いません。タイプがvalue変更された場合は、戻ってロギングステートメントも変更する必要があります。IDEが役に立たないもの。ロガーはデバッグを支援し、その邪魔にならないようにする必要があります。:-)
Chetan Narsude 2016年

3
@ChetanNarsude IntelliJ 2016は、少なくともフォーマット文字列がフォーマット引数に適合しない場合に通知します。例:String.format("%d", "Test")IntelliJ警告を生成しますArgument type 'String' does not match the type of the format specifier '%d'.。ただし、上記のソリューションで作業するときに、このインテリジェントな応答を提供できるかどうかはわかりません。
ときめき

これの速度は何ですか?
するThorbjörnRavnアンデルセン

@ThorbjørnRavnAndersen内部はかなり原始的ですが、もちろん静的ロガーよりも低速です
yegor256

slf4jをラップしていますか?それはslf4jを使用する目的を無効にしませんか?また、ログレベルが評価される前に文字列がフォーマットされるように、多くの人がString.formatを誤用しているのを見てきました。例えば、logger.info(String.format( "hello%s"、username))
ファンブスタマンテ

2

著者の観点からすると、主な理由は文字列連結のオーバーヘッドを減らすためだと思います。ロガーのドキュメントを読むだけで、次の単語を見つけることができます。

/**
* <p>This form avoids superfluous string concatenation when the logger
* is disabled for the DEBUG level. However, this variant incurs the hidden
* (and relatively small) cost of creating an <code>Object[]</code> before 
  invoking the method,
* even if this logger is disabled for DEBUG. The variants taking
* {@link #debug(String, Object) one} and {@link #debug(String, Object, Object) two}
* arguments exist solely in order to avoid this hidden cost.</p>
*/
*
 * @param format    the format string
 * @param arguments a list of 3 or more arguments
 */
public void debug(String format, Object... arguments);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.