Deeply nested if statements are a pain to read and maintain, so you should try to avoid them as much as possible. Here are a couple of suggestions on how reduce deeply nested if statements to a more manageable size.

Most of these suggestions can be applied to most languages that have the if statement, at least most object oriented or procedural languages. But my main focus when writing this were Java and PHP.

Early Return

Early returns should be used a lot more often by pretty much everybody. It’s one of the easiest ways to avoid or reduce deeply nested if statements and one of the first things I would look for when refactoring code.

The main idea is that when checking a value, the negative case is moved up-front, the error handled, and then the method is exited:

boolean test1 = ...;
if (test1) {
    boolean test2 = ...;
    if(test2) {
        boolean test3 = ...;
        if(test3) {
            // do the stuff
        } else {
            // some error, handle it
        }
    } else {
        // something else
    }
} else {
    // some other error, handle it
}
return;

Here, you can move the checks to the top of the method and remove three levels of nested if statements:

boolean test1 = ...;
if(!test1) {
    // some other error, handle it
    return;
}
boolean test2 = ...;
if(!test2) {
    // something else
    return;
}
boolean test3 = ...;
if(!test3) {
    // some error, handle it
    return;
}
// do the stuff
return;

Refactoring if-if

I don’t see this too often, but it does happen:

if (test1) {
    if(test2) {
        // do stuff
    }
}

Should be:

if (test1 && test2) {
    // do stuff
}

Refactoring if-if-else

This if condition occurs a bit more often than the previous one. Quite often, there might be a return in the second if statement, which makes it harder to grasp that // do even more stuff will be executed when test1 = true; test2 = false;

if(test1) {
    if(test2) {
        // do stuff
    }
} else {
    // do other stuff
}
// do even more stuff

A better way would be:

if (!test1) {
    // do other stuff
} else if (test2) {
    // do stuff
}
// do even more stuff

Use else if

This is another beginners mistake: not using else if:

if (test1) {
    // do stuff 1
} else {
    if (test2) {
        // do stuff 2
    } else {
        if (test3) {
            // do stuff 3
        }
    }
}

With else if you can avoid the nested if statements:

if (test1) {
    // do stuff 1
} else if (test2) {
    // do stuff 2
} else if (test3) {
    // do stuff 3
}

Move Code to its own Function

If you tried everything else, and your code is still too deeply nested, move some of the functionality to its own function, and give that function an expressive name to make your code easier to read.

Redundant Checks

You can introduce redundant checks to reduce the number of nested if statements.

I’m not that big of a fan of this approach (it is bad for performance and even though it reduces nesting, it might make the code harder to grasp), but if your code is very deeply nested and cannot be fixed otherwise, this might be useful to you. If the tests are complex, definitely save the result in a well named variable.

One example would be:

if (test1 && test2) {
    // do stuff
    if (test3 && test4) {
        // do more stuff
    }
    // do even more stuff
}

Which could be rewritten as:

if (test1 && test2) {
    // do stuff
}
if (test1 && test2 && test3 && test4) {
    // do more stuff
}
if (test1 && test2) {
    // do even more stuff
}