【发布时间】:2017-02-22 10:02:01
【问题描述】:
我正在使用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 在抱怨它
【问题讨论】:
标签: java string logging concatenation sonarlint