java - 内置字符串格式与字符串连接作为日志记录参数

我正在使用 SonarLint这向我显示了以下行中的一个问题。

LOGGER.debug("Comparing objects: " + object1 + " and " + object2);

旁注:包含此行的方法可能会被频繁调用。

这个问题的描述是

"Preconditions" and logging arguments should not require evaluation (squid:S2629)

Passing message arguments that require further evaluation into a Guava com.google.common.base.Preconditions check can result in a performance penalty. That's because whether or not they're needed, each argument must be resolved before the method is actually called.

Similarly, passing concatenated strings into a logging method can also incur a needless performance hit because the concatenation will be performed every time the method is called, whether or not the log level is low enough to show the message.

Instead, you should structure your code to pass static or pre-computed values into Preconditions conditions check and logging calls.

Specifically, the built-in string formatting should be used instead of string concatenation, and if the message is the result of a method call, then Preconditions should be skipped altoghether, and the relevant exception should be conditionally thrown instead.

Noncompliant Code Example

logger.log(Level.DEBUG, "Something went wrong: " + message);  // Noncompliant; string concatenation performed even when log level too high to show DEBUG messages

LOG.error("Unable to open file " + csvPath, e);  // Noncompliant

Preconditions.checkState(a > 0, "Arg must be positive, but got " + a); // Noncompliant. String concatenation performed even when a > 0

Preconditions.checkState(condition, formatMessage());  //Noncompliant. formatMessage() invoked regardless of condition

Preconditions.checkState(condition, "message: %s", formatMessage()); // Noncompliant

Compliant Solution

logger.log(Level.SEVERE, "Something went wrong: %s", message);  // String formatting only applied if needed

logger.log(Level.SEVERE, () -> "Something went wrong: " + message); //since Java 8, we can use Supplier , which will be evaluated lazily

LOG.error("Unable to open file {}", csvPath, e);

if (LOG.isDebugEnabled() {   LOG.debug("Unable to open file " + csvPath, e);  // this is compliant, because it will not evaluate if log level is above debug. }

Preconditions.checkState(arg > 0, "Arg must be positive, but got %d", a);  // String formatting only applied if needed

if (!condition) {   throw new IllegalStateException(formatMessage()); // formatMessage() only invoked conditionally }

if (!condition) {   throw new IllegalStateException("message: " + formatMessage()); }

我不能 100% 确定我是否理解正确。那么为什么这真的是一个问题。特别是关于使用字符串连接时性能影响的部分。因为我经常读到字符串连接比格式化要快。

编辑:也许有人可以解释一下

LOGGER.debug("Comparing objects: " + object1 + " and " + object2);

LOGGER.debug("Comparing objects: {} and {}",object1, object2);

在后台。因为我认为 String 在传递给方法之前会被创建。正确的?所以对我来说没有区别。但显然我错了,因为 SonarLint 在提示它

最佳答案

我相信你在那里有你的答案。

在条件检查之前计算连接。因此,如果您有条件地调用您的日志框架 10K 次并且所有这些都评估为 false,那么您将毫无理由地连接 10K 次。

同时检查 this topic .并查看 Icaro 的回答评论。

看看StringBuilder也是。

https://stackoverflow.com/questions/42388341/

相关文章:

formatting - Fortran 中带有前导零的格式化输出

postgresql - 如何为 PostgreSQL 设置千位分隔符?

ide - 保存文件时禁用重新格式化代码

php - 如何创建友好的日期格式(例如 "submitted 2 days ago")

javascript - 如何更改 winston 日志格式?

formatting - printf, sprintf 至少打印两位小数

c# - 在 Visual Studio 201x 中关闭 #region 的自动格式化

linux - 使用 *nix 中的 column 命令格式化列表

java - 删除 Eclipse 中的尾随空格——来自评论

javascript - 在格式化数字输入时验证数字输入