66

For my work I have to develop a small Java application that parses very large XML files (~300k lines) to select very specific data (using Pattern), so I'm trying to optimize it a little. I was wondering what was better between these 2 snippets:

if (boolean_condition && matcher.find(string)) {
    ...
}

OR

if (boolean_condition) {
    if (matcher.find(string)) {
        ...
    }
}

Other details:

  • These if statements are executed on each iteration inside a loop (~20k iterations)
  • The boolean_condition is a boolean calculated on each iteration using an external function
  • If the boolean is set to false, I don't need to test the regular expression for matches

Thanks for your help.

informatik01
  • 16,038
  • 10
  • 74
  • 104
3rgo
  • 3,115
  • 7
  • 31
  • 44
  • 2
    There is no easy answer. Check out [this SO discussion](http://stackoverflow.com/questions/1928712/how-to-split-up-complex-conditions-and-keep-short-circuit-evaluation) about the same topic. – Adriaan Koster Jul 12 '11 at 14:43
  • There's no performance difference whatsoever. It's purely a style matter, which makes it a matter of opinion. – Charles Duffy Dec 15 '21 at 02:53

10 Answers10

75

One golden rule I follow is to "Avoid Nesting" as much as I can. But if it is at the cost of making my single if condition too complex, I don't mind nesting it out.

Besides you're using the short-circuit && operator. So if the boolean is false, it won't even try matching!

So,

if (boolean_condition && matcher.find(string)) {
    ...
}

is the way to go!

informatik01
  • 16,038
  • 10
  • 74
  • 104
adarshr
  • 61,315
  • 23
  • 138
  • 167
  • 1
    Thanks ! I was not sure about the operator, if it was set to false, whether the matching would execute or not. – 3rgo Mar 10 '11 at 13:05
  • 12
    Consider `if(x != null && x.isY())`; if `&&` *didn't* short-circuit the evaluation, that would blow up in your face the instant x == null. – user Mar 10 '11 at 13:13
  • 1
    Yeah indeed ! But I had to be sure, so I asked – 3rgo Mar 10 '11 at 13:24
  • +adarshr well it will also short-circuit even in the nested if, since if outer if evaluates to false then it wont bother to check the inner if, same as the && thing if first one evaluates to false it will short circuit – Shreyan Mehta Mar 09 '18 at 07:46
  • @user wouldn't you check for null, prior to evaluation, though? Common sense says yes? ArgumentNullException perhaps? – D3vtr0n Oct 29 '21 at 14:55
  • If you were using multiple operation on the null statement, then yes. But if it is something like a leaf node of a tree, then simple condition (or null propagation like in C#) is good enough. – Ferazhu Sep 23 '22 at 22:55
24

The following two methods:

public void oneIf(boolean a, boolean b)
{
    if (a && b)
    {   
    }
}

public void twoIfs(boolean a, boolean b)
{
    if (a)
    {
        if (b)
        {       
        }
    }
}

produce the exact same byte code for the method body so there won't be any performance difference meaning it is purely a stylistic matter which you use (personally I prefer the first style).

Jonathan
  • 3,203
  • 2
  • 23
  • 25
  • 7
    I wouldn't wonder if the method `public void noIfs(boolean a, boolean b) {}` produced the same byte code too ;-) – Axel Mar 10 '11 at 13:23
  • 2
    @Axel no, it doesn't (I just checked!) Not surprising really, the Java compiler does very little optimisation, leaving it to the JVM to do at runtime. – Jonathan Mar 10 '11 at 13:48
  • I think parser has more work to do in the second construct, since it has to figure out whether next statement is 'if' or something else. On the other hand, in the 1st construct, it will only parse the condition, and knows that following is a part of condition. – kvaibhav Dec 20 '16 at 04:22
7

Both ways are OK, and the second condition won't be tested if the first one is false.

Use the one that makes the code the more readable and understandable. For just two conditions, the first way is more logical and readable. It might not be the case anymore with 5 or 6 conditions linked with &&, || and !.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
4

I recommend extracting your expression to a semantically meaningful variable and then passing that to your evaluation. Instead of:

if (boolean_condition && matcher.find(string)) { ... }

Assign the expression to a variable, then evaluate the variable:

const hasItem = boolean_condition && matcher.find(string)

if (hasItem) { ... }

With this method, you can keep even the most complex evaluations readable:

const hasItem = boolean_condition && matcher.find(string)

const hasOtherThing = boolean_condition || boolean_condition

const isBeforeToday = new Date(string) < new Date()

if (hasItem && hasOtherThing && isBeforeToday) { ... }
55 Cancri
  • 1,075
  • 11
  • 23
3

I tend to see too many && and || strung together into a logic soup and are often the source of subtle bugs.

It is too easy to just add another && or || to what you think is the right spot and break existing logic.

Because of this as a general rule i try not to use either of them to avoid the temptation of adding more as requirements change.

sm14
  • 119
  • 2
3

If you like to be compliant to Sonar rule squid:S1066 you should collapse if statements to avoid warning since it states:

Collapsible "if" statements should be merged

Petter Friberg
  • 21,252
  • 9
  • 60
  • 109
3

Java uses short-circuiting for those boolean operators, so both variations are functionally identical. Therefore, if the boolean_condition is false, it will not continue on to the matching

Ultimately, it comes down to which you find easier to read and debug, but deep nesting can become unwieldy if you end up with a massive amount of braces at the end

One way you can improve the readability, should the condition become longer is to simply split it onto multiple lines:

if(boolean_condition &&
   matcher.find(string))
{
    ...
}

The only choice at that point is whether to put the && and || at the end of the previous line, or the start of the current.

Farrell
  • 508
  • 3
  • 11
2

The first one. I try to avoid if nesting like that, i think it's poor style/ugly code and the && will shortcircuit and only test with matcher.find() if the boolean is true.

Robby Pond
  • 73,164
  • 16
  • 126
  • 119
1

In terms of performance, they're the same.

  • But even if they weren't

what's almost certain to dominate the time in this code is matcher.find(string) because it's a function call.

Mike Dunlavey
  • 40,059
  • 14
  • 91
  • 135
0

Most would prefer to use the below one, because of "&&".

if (boolean_condition && matcher.find(string)) {
...
}

We normally called these as "short-circuit (or minimum evaluation)". It means the 2nd argument (here it is "matcher.find(string)") is only evaluated only if the 1st argument doesn't have sufficient information to determine the value of the expression. As an example, if the "boolean_condition" is false, then the overall condition must be false (because of here logical AND operator). Then compiler won't check the 2nd argument which will cause to reduce the running time of your code.

TTDS
  • 114
  • 1
  • 10
  • Isn't this already covered by existing answers? (And more importantly -- this might have been considered on-topic in 2011, but in 2021 this question is unambiguously too opinion-based to be on-topic, meaning the _Answer Well-Asked Questions_ section of [How to Answer](https://stackoverflow.com/help/how-to-answer) applies). – Charles Duffy Dec 15 '21 at 02:54