2

I see the main purpose of continue in programming, it can get you out from the rest of loop steps like:

while(condition1){
  ... code ...
  if(!condition2){
    continue;
  }
  ... code ...
  if(condition3){
    break;
  }
  ... code ...
}

I understand that condition2 and condition3 might depend on the inner code so it makes handy to make a separate escape route from loop step. But does it mean the code should be refactored instead building escape routes, like rethinking the original condition1?

I would say if I need several continue and break parts, I feel bad about my code, usually I am working without continue and I don't really miss it.

An another use of continue and break which I can accept is optimalization, but I still have the same feeling about it like I told above. For some reasons I have feeling "using GOTO". Am I right, if I am not, why?

CsBalazsHungary
  • 1,389
  • 3
  • 13
  • 15
  • If the loop is short continue and break might help readability. I prefer seeing a if(precondition) {continue;} instead of if(!precondition){ some operation } since the less indented the code is the better is for me (and hopefully for other) to read. – Fabio Marcolini Jul 22 '14 at 12:15
  • 1
    See also: http://stackoverflow.com/questions/18188123/is-it-bad-practice-to-use-break-to-exit-a-loop-in-java And: http://programmers.stackexchange.com/questions/58237/are-break-and-continue-bad-programming-practices – FrustratedWithFormsDesigner Jul 22 '14 at 13:54

2 Answers2

6

Correction: continue gets you out of one iteration of a loop, not out of the entire loop.

Skipping the rest of an iteration of a loop is a lot like returning early from a method call (in fact, a lot of long loop bodies should be method calls). So the same arguments apply as for "return early or use nested if?", which is already a well-known, divisive controversy; I doubt you'll achieve a consensus about this question either.

My own position is: continue is a keyword for a reason; it is in no way automatically bad the way most people think goto is bad.

Kilian Foth
  • 107,706
  • 45
  • 295
  • 310
  • You are right, I am correcting, actually it splits into two question in the same kind. – CsBalazsHungary Jul 22 '14 at 12:05
  • 3
    +1: The main difference between `continue` and `goto`: With `continue` you know, where you jump to (the beginning of the loop), but with `goto` your destination may be anywhere. – Residuum Jul 22 '14 at 12:10
  • well yes, but it doesn't change the essential meaning of continue, using these tools feels like I am damaging the code readability. – CsBalazsHungary Jul 22 '14 at 12:13
  • 1
    @CsBalazsHungary - If your loop body is long, and sprinkled with several continues and breaks, it will CERTAINLY hurt readability. But if you keep the loop body short and are careful how these things are used, then it's no problem to use them while keeping code readable. As usual, it's a balance that you have to strike for your code. – Michael Kohne Jul 22 '14 at 12:24
  • @MichaelKohne: a long loop body hurts readability. Continue statements make it even worse. – kevin cline Jul 22 '14 at 13:02
  • 3
    @kevincline - Right. But if you've got a long loop body, you've ALREADY got a problem. Even without continue, a long loop body is hard to read. I'm saying that with a short loop body, continue can be used in a readable manner. – Michael Kohne Jul 22 '14 at 13:03
  • I couldn't have said it better. This is exactly what I think. – Gaston Sanchez Jan 28 '16 at 00:35
5

The classic goto has different forms with various restrictions on them. Be it return, try{} catch{}, throw, break, or continue. They are all really goto with some additional bits around it.

One could refactor the continue or break into another looping style with return:

for (int i = 0; i <= max; i++) {
  if(someTest) { continue; }
  if(someOtherTest) { continue; }
  doStuff;
}

Can be written as:

for (int i = 0; i <= max; i++) {
  func();
}
....

void func() {
  if(someTest) { return; }
  if(someOtherTest) { return; }
  doStuff;
}

Which is easier to read? Well, I'd tend to argue that the first is because the second loses the context of the loop... but they're otherwise the same. Its just that people tend to see less of continue than they do of return in everyday code.

From Java Tutorials : Branching Statements break and continue when used with labels have a bit more power than most people realize. It also makes the code a bit more explicit as to which loop is being acted upon by the control statement. Consider:

class ContinueWithLabelDemo {
    public static void main(String[] args) {
        String searchMe = "Look for a substring in me";
        String substring = "sub";
        boolean foundIt = false;

        int max = searchMe.length() -  substring.length();

    test:
        for (int i = 0; i <= max; i++) {
            int n = substring.length();
            int j = i;
            int k = 0;
            while (n-- != 0) {
                if (searchMe.charAt(j++) != substring.charAt(k++)) {
                    continue test;
                }
            }
            foundIt = true;
            break test;
        }
        System.out.println(foundIt ? "Found it" : "Didn't find it");
    }
}

Note that the continue and the break are used with a label that specifies what loop they continue or break to (the label on break isn't necessary because its only one level, but helps in the comprehension of the code).

If you really wanted to, you could refactor this code to:

public class Demo {
    public static void main(String[] args) {
        String searchMe = "Look for a substring in me";
        String substring = "sub";
        boolean foundIt;

        int max = searchMe.length() - substring.length();

        foundIt = loop2(searchMe, substring, max);
        System.out.println(foundIt ? "Found it" : "Didn't find it");
    }

    private static boolean loop2(String searchMe, String substring, int max) {
        for (int i = 0; i <= max; i++) {
            if (loop(searchMe, substring, i)) {
                return true;
            }
        }
        return false;
    }

    private static boolean loop(String searchMe, String substring, int j) {
        int n = substring.length();
        int k = 0;
        while (n-- != 0) {
            if (searchMe.charAt(j++) != substring.charAt(k++)) {
                return false;
            }
        }
        return true;
    }
}

(I think I did that refactoring right though there are certainly bits in there to grumble about) ... but I'm really not sure what that gains you. And those two methods with multiple returns will draw the wrath of the "multiple returns are an anti-pattern" crowd (which have just as valid points as the continue and break are anti-patterns crowd - and in the above case, likely more justified wrath too). Yes, this could again be written in a way that makes use of other tests that will make the "arrow is an anti-pattern" people look at you funny.

continue is a guard statement in a loop. break is a early return.

Because something isn't used much doesn't make it an anti pattern. It just means that people aren't as familiar with it.


As an aside, goto is seeing a bit of a comeback in C# where it can be used with restrictions (note that C# doesn't have a labeled break like Java does and thus without going through the hoops of extracting methods, this is the way to write the code).