Slow performance of many if-else statements in Java

I have a method that checks all combinations of 5 different conditions with 32 if-else statements (think about the truth table). The 5 different letters are methods that each run their own regular expressions in a string and return a boolean value indicating whether the string matches the regular expression. For example:

if(A,B,C,D,E){ }else if(A,B,C,D,!E){ }else if(A,B,C,!D,!E){ }...etc,etc. 

However, this does affect the performance of my application (sorry, I cannot go into too many details). Can anyone recommend a better way to deal with this logic?

Each method using regex looks like this:

 String re1 = "regex here"; Pattern p = Pattern.compile(re1, Pattern.DOTALL); Matcher m = p.matcher(value); return m.find(); 

Thanks!

+7
source share
10 answers

You can try

 boolean a,b,c,d,e; int combination = (a?16:0) + (b?8:0) + (c?4:0) + (d?2:0) + (e?1:0); switch(combination) { case 0: break; // through to case 31: break; } 
+17
source

represent each condition as a bit, check each condition once and set the corresponding flag in one int. then include the int value.

 int result = 0; if(A) { result |= 1; } if(B) { result |= 2; } // ... switch(result) { case 0: // (!A,!B,!C,!D,!E) case 1: // (A,!B,!C,!D,!E) // ... } 
+7
source

Without knowing the details, it may be useful to arrange the if statements in such a way that the last ones that do the heavy lifting are executed. This suggests that other conditions will be true, thereby avoiding the "heavy" climbs together. In short, use short circuits if possible.

+2
source

All the above answers are incorrect, because the correct answer to the optimization question is: Measure! Use the profiler to measure where your code is wasting its time.

Having said that, I would argue that the biggest victory is to avoid compiling regular expressions more than once. And after that, as others suggested, evaluate each condition only once and save the results in Boolean variables. So thait84 has a better answer.

I’m also willing to argue for jtahlborn and Peter Lawrey that Salvatore Previti’s proposals are (in fact, the same), but smart, although they will get you a slight additional benefit if you don’t work on 6502 ...

(This answer says that I am full of it, so in the interest of full disclosure, I should mention that I am actually hopeless in optimization, but measurement is still the correct answer.)

+2
source

Run the regex once for each line and save the results in booleans and just do if / else in booleans instead of regex. Also, if you can, try reusing the precompiled version of your regular expression and reusing it.

+1
source

One possible solution: use a switch that creates a binary value.

 int value = (a ? 1 : 0) | (b ? 2 : 0) | (c ? 4 : 0) | (d ? 8 : 0) | (e ? 16 : 0); switch (value) { case 0: case 1: case 2: case 3: case 4: ... case 31: } 

If you can avoid switching and using an array, this will be faster.

+1
source

Perhaps split it into layers, for example:

 if(A) { if(B) { //... the rest } else { //... the rest } } else { if(B) { //... the rest } else { //... the rest } } 

However, there seems to be a better way to do this.

+1
source

I have a solution with EnumSet. However, this is too verbose, and I suppose I prefer @Peter Lawrey's solution.

Effective Java by Bloch recommends using EnumSet over bit fields, but I would make an exception here. However, I posted my solution because it might be useful for someone with a slightly different problem.

 import java.util.EnumSet; public enum MatchingRegex { Tall, Blue, Hairy; public static EnumSet<MatchingRegex> findValidConditions(String stringToMatch) { EnumSet<MatchingRegex> validConditions = EnumSet.noneOf(MatchingRegex.class); if (... check regex stringToMatch for Tall) validConditions.add(Tall); if (... check regex stringToMatch for Blue) validConditions.add(Blue); if (... check regex stringToMatch for Hairy) validConditions.add(Hairy); return validConditions; } } 

and you use it as follows:

 Set<MatchingRegex> validConditions = MatchingRegex.findValidConditions(stringToMatch); if (validConditions.equals(EnumSet.of(MatchingRegex.Tall, MathchingRegex.Blue, MatchingRegex.Hairy)) ... else if (validConditions.equals(EnumSet.of(MatchingRegex.Tall, MathchingRegex.Blue)) ... else if ... all 8 conditions like this 

But that would be more efficient:

 if (validConditions.contains(MatchingRegex.Tall)) { if (validConditions.contains(MatchingRegex.Blue)) { if (validConditions.contains(MatchingRegex.Hairy)) ... // tall blue hairy else ... // tall blue (not hairy) } else { if (validConditions.contains(MatchingRegex.Hairy)) ... // tall (not blue) hairy else ... // tall (not blue) (not hairy) } else { ... remaining 4 conditions } 
+1
source

You can also adapt your if / else to the switch / case (which I understand faster)

0
source

preliminary generation of A, B, C, D, and E as Boolean, rather than evaluating them in if condition blocks, would ensure both readability and performance. If you are also concerned about performance in different cases, you can organize them as a tree or combine them into one whole (X = (A? 1: 0) | (B? 2: 0) | ... | (E? 16: 0 )) that you would use in switch .

0
source

All Articles