简体   繁体   English

改进if-else语句的圈复杂度代码

[英]Improve the cyclomatic complexity code for if-else statements

I have a block of if-else statements in a method for which I am getting cyclomatic complexity issue. 我在遇到循环复杂性问题的方法中有一块if-else语句。 I have tried using switch statement for this but still the issue remains. 我尝试为此使用switch语句,但问题仍然存在。

if (fileName.startsWith(HwErrorsEtlConstants.MR_RAW_GRADIENT_ERRORS)) {
    method1()...
} else if (fileName.startsWith(HwErrorsEtlConstants.MR_RAW_PFEI_ERRORS)) {
    method2()...
} else if (fileName.startsWith(HwErrorsEtlConstants.MR_RAW_RFAMP_ERRORS)) {
    method3()...
} and so on...

public static void method1(IOutputWriter writer, String fileName, InputStream fileInputStream) throws IOException {
        //logic for the method
    }

Edit : as you mentioned you have checked Exception s that can be thrown and arguments in your method. 编辑 :如前所述,您已经检查了可以抛出的Exception 方法中的参数。 As a Runnable doesn't declare that it can throw Exceptions and also doens't accept any parameters you have to create your own FunctionalInterface (click here to see what they really are): 由于Runnable并未声明它会引发Exceptions并且也不接受您必须创建自己的FunctionalInterface任何参数(请单击此处查看其真正含义):

public interface ThrowingRunnable {
    void run(IOutputWriter writer, String fileName, InputStream fileInputStream) throws IOException;
}

Then you just have to replace Runnable with ThrowingRunnable in my earlier proposed code below and you should be fine. 然后,只需在下面我先前建议的代码中用ThrowingRunnable替换Runnable ,就可以了。


You can create a mapping of HwErrorsEtlConstants to the specific method (uses java 8): 您可以创建HwErrorsEtlConstants到特定方法的映射(使用Java 8):

static final Map<String, Runnable> MAPPING;
static {
    Map<String, Runnable> temp = new HashMap<>();
    temp.put(HwErrorsEtlConstants.MR_RAW_GRADIENT_ERRORS, this::method1);
    temp.put(HwErrorsEtlConstants.MR_RAW_PFEI_ERRORS, this::method2);
    temp.put(HwErrorsEtlConstants.MR_RAW_RFAMP_ERRORS, this::method3);
    MAPPING = Collections.unmodifiableMap(temp);
}

Then in your method you can use Stream s introduced also in Java 8: 然后,在您的方法中,可以使用Java 8中也引入的Stream

// Optional indicates a potentially absent value, it's just a wrapper around a Runnable
Optional<Runnable> optional = MAPPING
    // create a Stream from the entries
    .entrySet().stream()
    // keep the items that match the condition and drop every other
    .filter(e -> filename.startsWith(e.getKey()))
    // we had Map.Entry<String, Runnable>, but now we only need the value e.g. the Runnable
    .map(Map.Entry::getValue)
    // short circuit, e.g. we only want the first value that matches
    .findFirst();

// checks if anything is present, this is used as the MAPPING "could" be empty
if(optional.isPresent()) {
    // unpack the value and call it with arguments
    optional.get().run(aWriter, someFileName, anInputStream);
} else {
    // nothing matched, throw error or log etc.
}

Though as has been mentioned, your current solution does look fine, I guess you're using Sonar for code analysis. 尽管如上所述,您当前的解决方案确实不错,但是我想您正在使用Sonar进行代码分析。 Sometimes Sonar just has false positives, so you can also safely ignore them. 有时,Sonar只会产生误报,因此您也可以放心地忽略它们。

Further reads to help you understand Java 8: 进一步阅读以帮助您了解Java 8:

The cyclomatic complexity is one issue: indeed cycles . 圈复杂度是一个问题:确实是循环

Then there is the splitting of the flow on a property using if/switch, which is not object-oriented. 然后使用if / switch(不是面向对象的)在属性上拆分流。 It also may violate separation of concerns : having many methods handling entirely different smaller aspects. 它还可能违反关注点分离 :拥有许多处理完全不同的较小方面的方法。

If the number of fields is larger, and the number of lines is large, consider extracting classes handling one aspect. 如果字段数较大,并且行数较大,请考虑提取处理一个方面的类。

For reduction of the cyclomatic complexity, check to control flow of the callers, repetitions of the same call, practical duplicate code. 为了降低循环复杂性,请检查以控制调用者的流程,同一呼叫的重复,实用的重复代码。 And then try to (re-)move cycles. 然后尝试(重新)移动循环。 Best is when you can put cycles together; 最好的是可以将各个周期放在一起。 and work on Lists/Sets/Streams. 并处理列表/集合/流。

You can solve this via Java 8 approach using Predicate & Function functional interfaces. 您可以使用谓词和函数功能接口通过Java 8方法解决此问题。 You have to put all the conditions through predicates and in Function, you can add implementation which needs to be executed when condition matches. 您必须通过谓词放置所有条件,并且在Function中,可以添加条件匹配时需要执行的实现。

Map<Predicate,Function<String,String>> map = new HashMap<>();

    Predicate<String> p = (fileName)->fileName.startsWith(HwErrorsEtlConstants.MR_RAW_GRADIENT_ERRORS);

  Function<String,String> method = (input)->{ return "output";}; 

   map.put(p,method);
    Optional<String> result =
    map.entrySet()
    .stream()
    .filter(entry->entry.getKey().test(fileName))
    .map(entry->entry.getValue().apply())
    .findFirst();

OR 要么

  map.entrySet()
    .stream()
    .filter(entry->entry.getKey().test(fileName))
    .forEach(entry->entry.getValue().apply());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM