Can high cyclomatic complexity (warnings) be avoided when using switch-case on a large enum?
cyclomatic-complexity, enums, java, sonarqube
Solution
Instead of using a large switch statement you can use the enums to build a state machine. What you do is take the code to parse the text in each case block, and put this in a method for each of the enum states.
From example
enum States implements State {
XML {
public boolean process(Context context) {
if (context.buffer().remaining() < 16) return false;
// read header
if(headerComplete)
context.state(States.ROOT);
return true;
}
}, ROOT {
public boolean process(Context context) {
if (context.buffer().remaining() < 8) return false;
// read root tag
if(rootComplete)
context.state(States.IN_ROOT);
return true;
}
}
}
public void process(Context context) {
socket.read(context.buffer());
while(context.state().process(context));
}
From Using an enum as a State Machine
Problem
Assume a method chooses an action depending on a value from a fairly large enum. Our Sonar now complains about a high cyclomatic complexity (of about the number of case statements, naturally) of this method. I know, large switch case statements are not really best style in OOP, but sometimes it is quite opportune to use them (in my case a parser evaluating operator tokens) instead of building a complex object tree. My concern now how to deal with that? Is there any design pattern to split such a switch case meaningfully? Or can I (and should I) exclude the class from measuring CC (as there may be other methods in it where a high CC can easily be avoided)? It is not a really a critical thing; I just dislike my project having warnings that I can't remove ;o) Edit: code sample ``` String process() String fieldName = this.getField() != null ? this.getField().getSchemaName() : null; String result = ""; switch (op) { case PHRASE: result = ""; if(!value.isEmpty() && value.get(0) != null) { result = value.get(0).toString(); } break; case EQUALS: case GT: case GTE: case LT: case LTE: case NOT_EQUALS: result = prepareSingleParameterStatement(fieldName); break; case BETWEEN_EXC: case BETWEEN_INC: result = prepareDoubleParameterStatement(fieldName); break; case IN: case NOT_IN: case ALL_IN: result = prepareCollectionStatement(fieldName); break; case AND: case OR: result = prepareLogicalStatement(); break; case NOT: result = prepareNotStatement(); break; default: break; } return result; } ```