【问题标题】:Fix for Cognitive Complexity for multiple if else conditions in Java修复 Java 中多个 if else 条件的认知复杂性
【发布时间】:2021-02-17 22:54:57
【问题描述】:

这是我运行良好的代码。但是当我推送代码时,sonarqube 质量门由于认知复杂性而失败。有关解决此声纳问题的任何想法

if (bbResponse.getEmails() != null && !bbResponse.getEmails().isEmpty()) {

        bbResponse.getEmails().stream().forEach((BBEmail bbEmail) -> {
            if ("CHK".equals(bbEmail.getSEQ())) {
                //CODE
            } else if ("CHT".equals(bbEmail.getSEQ())) {
                //CODE
            } else if ("MYT".equals(bbEmail.getSEQ())) {
                //CODE
            } else {
                throw new IllegalStateException();
            }
        });
    }

【问题讨论】:

  • 您也可以使用switch 语句来执行此操作(除非您使用的是 Java 的超旧版本)。但我不知道 Sonarqube 是否会认为这不那么复杂。
  • 进一步简化。嗯.. 尝试为这些声明标识符:bbResponse.getEmails()bbEmail.getSEQ()

标签: java sonarqube sonarqube-scan


【解决方案1】:

一些想法(不知道是否满足Sonarqube):

  • 测试bbResponse.getEmails().isEmpty() 不是必需的。空列表上的forEach() 完全有效,将执行其主体零次。

  • 正如在 cmets 中已经写的那样,您可以用 switch 语句替换字符串比较条件。

  • 您可以将 lambda 表达式重构为自己的方法,并在 forEach() 调用中使用方法引用。

  • 您可以将帖子中以//CODE 给出的块重构为它们自己的方法,如果它们的长度超过几行的话。

顺便说一句:

虽然 Sonarqube 肯定会提供有价值的建议,但我绝不会将其设为硬质量门。

让一个规则有些模糊的自动机决定可接受的代码风格对我来说似乎不是一个好主意。我们都想要干净、人类可读的代码,这与 Sonarqube 兼容的代码不同。

例如Sonarqube 无法判断可读性最重要的方面:类、字段、变量等的命名。你的问题表明,例如复杂性规则拒绝任何开发人员都不会判断为“难以阅读”的代码(除非您省略的“CODE”块过长)。

【讨论】:

    【解决方案2】:
    1. 如果使用stream(),检查非空列表可能是多余的,_以及forEach 可以在不调用.stream() 的情况下使用
    2. 可以为特定代码准备消费者方法图
    3. 从映射中获取可为空的使用者或引发异常时使用Optional::ifPresentOrElse
    static void handleEmails(List<BBEmail> emails) {
    
        if (null != emails) {
            Map<String, Consumer<BBEmail>> codes = Map.of(
                    "CHK", MyClass::processChkEmail,
                    "CHT", MyClass::processChtEmail,
                    "MYT", MyClass::processMytEmail
            );
            emails.orEach(bbEmail -> 
                      Optional.ofNullable(codes.get(bbEmail.getSEQ()))
                              .ifPresentOrElse(consumer -> consumer.accept(bbEmail),
                                               () -> {throw new IllegalStateException();}
                              )
                  );
        }
    }
    
    static void processChkEmail(BBEmail email) {
        // TODO CHK
    }
    
    static void processChtEmail(BBEmail email) {
        // TODO CHT
    }
    
    static void processMytEmail(BBEmail email) {
        // TODO MYT
    }
    

    这应该可以解决声纳问题,但我不太确定它会增加人类的可读性:)


    前面提到的另一个选项是switch 语句——对于没有break 语句的Java 12+ 语法,它可以更加简洁:

    static void handleEmailSwitchJava12(List<BBEmail> emails) {
        if (null != emails) {
            emails.forEach(bbEmail -> {
                switch (bbEmail.getSEQ()) {
                    case "CHK" -> processChkEmail(bbEmail);
                    case "CHT" -> processChtEmail(bbEmail); 
                    case "MYT" -> processMytEmail(bbEmail);
                    default -> throw new IllegalStateException("Invalid SEQ code: " + bbEmail.getSEQ());
                }
            });
        }
    }
    

    【讨论】:

    • 谢谢亚历克斯。但它肯定会使阅读变得更加复杂:)
    • @Syed, switch 版本更具可读性。但是,如果您摆脱 isEmpty 检查并直接使用 emails.forEach 它应该会降低“复杂性”并满足声纳:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多