Amunak Amunak - 18 days ago 7
Java Question

How to make complex conditions look nice and save the number of statements?

In my java application I have a huge set of conditions which decides just one action. My question is how to make it look nice (I use NetBeans so I'd prefer solution that will not be broken by its code formatting function). I'd also like to have there as low amount of if/else statements as possible, because I think it will make it faster.

My original code was a mess, so I made an action diagram:complex action diagram full of conditions. Take a copy if you want to play with it. Please keep in mind that the diagram is not perfect as to UML syntax, partly because I made it using google docs.

This is the code:

if (!config.get("checkForSpecials") || event.isNotSpecial()) {
if (config.get("filterMode").equals("blacklist")) {
if (!itemFilter.contains(event.getItem().getName())) {
item.process();
}
} else if (config.get("filterMode").equals("whitelist")) {
if (itemFilter.contains(event.getItem().getName())) {
item.process();
}
} else {
item.process();
}
}


There are two things I don't like about it - the conditions are not too clear (especially when I unfold full method names and config strings), and the fact that the process method call is there three times.

Answer

Factoring booleans out and caching return values from method calls can help clarify code.

In addition, plotting all the outcomes on a logic table can help. I use this tool to help.

With the linked tool:

A: config.get("filterMode").equals("blacklist")
B: config.get("filterMode").equals("whitelist")
C: filterContainsName (see below)

The tool churns out:

(!A && !B) || (!A && C) || (A && !C)

Which leads to the code below (with a small tweak that replaces (!A && C) with (B && C)):

boolean filterContainsName = itemFilter.contains(event.getItem().getName());
boolean useBlacklist       = config.get("filterMode").equals("blacklist");
boolean useWhitelist       = config.get("filterMode").equals("whitelist");

if (!config.get("safeMode") || event.isSafe()) {
    if((!useBlackList && !useWhiteList) ||
       ( useWhiteList &&  filterContainsName) ||
       ( useBlackList && !filterContainsName)) {
        item.process();
    }
}