【问题标题】:SonarQube: Invoke method(s) only conditionallySonarQube:仅有条件地调用方法
【发布时间】:2017-11-03 14:37:33
【问题描述】:

以下代码部分在 SonarQube 中引发了一个主要错误: “仅有条件地调用方法。”
我该如何解决这个问题?

if(us != null){
    logger.info("Log this: {}", us.toString());
}

【问题讨论】:

  • 您可以关闭该检查还是您的项目需要它?
  • @QBrute 我不想“关闭它”,我想知道为什么这仍然会引发错误,因为应用了 if() 这是推荐的解决方案之一。和/或解决方案。
  • 您使用哪个日志框架?您在 SonarQube 实例上使用哪个版本的 SonarJava 插件?
  • 也许 sonarqube 指的是“boolean isInfoEnabled()”,你应该使用它。哪一行是主要错误?
  • @TiborBlenessy log4j 1.2.17 和 sonar-maven-plugin 3.2,以防它对任何人有帮助。

标签: java logging sonarqube


【解决方案1】:

us.toString() 的调用是多余的,无论配置的日志级别如何,都会调用toString() 方法。您应该只将us 作为参数传递给info,而不需要if 语句。

logger.info("Log this: {}", us);

【讨论】:

  • 这个答案真的正确吗?在我的情况下,警告是通过在答案中使用相同的语法引发的。
  • @Funder 你能分享完整的代码示例吗?我可以调查一下
  • 我们去@Tibor Blenessy gist.github.com/funder7/928484ff56b5db999d8472a931db14c4。我已经包含了该方法接收到的类,以备不时之需。谢谢!
【解决方案2】:

正如问题的 cmets 所述,另一个可行的答案是:

if(logger.isInfoEnabled() && us != null){
    logger.info("Log this: {}", us.toString());
}

【讨论】:

  • 这很有帮助
【解决方案3】:

您可以忽略这一点,但如果可能的话,处理这种情况可能会很好,这将有助于我们处理和切断不必要的计算。

这里建议的一件事是检查您要使用的日志级别是否已启用。

if(logger.isInfoEnabled() && us != null){
    // this inner code will only get executed if the above is true
    logger.info("Log this: {}", us.toString());
}

想象有一个复杂的任务在里面运行,如果你不打算记录它,如果日志级别被禁用,那将是浪费时间。 Logger 将在内部为您检查,但现在在调用 .info() 之前执行此操作将为您节省一些周期。

【讨论】:

    【解决方案4】:

    将需要进一步评估的消息参数传递到 Guava com.google.common.base.Preconditions 检查可能会导致性能下降。这是因为无论是否需要它们,每个参数都必须在实际调用方法之前解决。

    同样,将连接的字符串传递给日志记录方法也会导致不必要的性能损失,因为每次调用该方法时都会执行连接,无论日志级别是否低到足以显示消息。

    相反,您应该构建代码以将静态或预先计算的值传递到前提条件检查和记录调用。

    具体来说,应该使用内置字符串格式而不是字符串连接,如果消息是方法调用的结果,则应该完全跳过前置条件,而是有条件地抛出相关异常。

    不合规代码示例

        logger.log(Level.DEBUG, "Something went wrong: " + message);  
    // Noncompliant; string concatenation performed even when log level too high to show DEBUG messages
        
        logger.fine("An exception occurred with message: " + message); 
    // Noncompliant
        
        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: {0} ", message);  
    // String formatting only applied if needed
        
        logger.fine("An exception occurred with message: {}", message);  
    // SLF4J, Log4j
        
        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 {0}", 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());
        } 
    

    例外

    catch 块被忽略,因为性能损失在异常路径上并不重要(catch 块不应成为标准程序流的一部分)。 Getter 以及在注释上调用的方法都被忽略,这些方法可以被视为 getter。此规则说明使用 SLF4J 方法 isXXXEnabled 进行显式测试级测试,并忽略此类 if 语句的主体。

    【讨论】:

      【解决方案5】:

      简单的回答:只需从您的代码中删除 .toString,因为格式化程序会为您将其更改为 String。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-11-01
        • 1970-01-01
        • 2023-01-27
        • 1970-01-01
        • 2020-07-03
        • 2017-02-14
        • 1970-01-01
        • 2015-07-11
        相关资源
        最近更新 更多