Reputation: 895
I have a block of if-else statements in a method for which I am getting cyclomatic complexity issue. I have tried using switch statement for this but still the issue remains.
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
}
Upvotes: 2
Views: 1429
Reputation: 19926
Edit: as you mentioned you have checked Exception
s that can be thrown and arguments in your method. 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):
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.
You can create a mapping of HwErrorsEtlConstants
to the specific method (uses 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:
// 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. Sometimes Sonar just has false positives, so you can also safely ignore them.
Further reads to help you understand Java 8:
Stream
javadocOptional
javadocUpvotes: 3
Reputation: 2551
You can solve this via Java 8 approach using Predicate & Function functional interfaces. You have to put all the conditions through predicates and in Function, you can add implementation which needs to be executed when condition matches.
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());
Upvotes: 1
Reputation: 109547
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. 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.
Upvotes: 2