我正在使用 SonarLint ,它在下一行中向我显示了一个问题。
LOGGER.debug("Comparing objects: " + object1 + " and " + object2);
旁注:包含此行的方法可能会经常被调用。
这个问题的描述是
“先决条件”和日志记录参数不应要求评估(鱿鱼:S2629)
将需要进一步评估的消息参数传递到 Guava com.google.common.base.Preconditions 检查中可能会导致性能下降。这是因为无论是否需要它们,每个参数都必须在实际调用方法之前解析。
同样,将连接的字符串传递到日志记录方法中也会导致不必要的性能损失,因为每次调用该方法时都会执行连接,无论日志级别是否低到足以显示消息。
相反,您应该构建代码以将静态或预先计算的值传递到 Preconditions 条件检查和记录调用中。
具体来说,应该使用内置的字符串格式而不是字符串连接,如果消息是方法调用的结果,则应该完全跳过前提条件,而是有条件地抛出相关异常。
不合规代码示例
> 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 > > ``` > > 合规解决方案 > > ``` > 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 正在抱怨它
原文由 Naxos84 发布,翻译遵循 CC BY-SA 4.0 许可协议
我相信你在那里有答案。
连接是在条件检查之前计算的。因此,如果您有条件地调用您的日志记录框架 10K 次并且所有这些都评估为 false,那么您将无缘无故地连接 10K 次。
另请检查 此主题。并查看 Icaro 的回答评论。
也看看 StringBuilder 。