开发者

Java Continue Label is Deprecated?

开发者 https://www.devze.com 2023-03-19 04:02 出处:网络
I have 2 fors, after the nested for I have some code which I don\'t want to execute if a condition is true inside the nested for. If I use break that code would execute, so (as I learned in SCJP) I us

I have 2 fors, after the nested for I have some code which I don't want to execute if a condition is true inside the nested for. If I use break that code would execute, so (as I learned in SCJP) I used continue label; for the outer for. Is this a deprecated usage of Java ? Old fashioned ? Somebody suggested to use recursion or something else, but for me this is perfectly normal, simple, up-to-date and the perfect way of doing it.

here:
for (bla bla) {
   for (bla bla) {
      if (whatever) continue here;
   }
// some code I don't want to execute if whatever is true
}

Thanks

Edited:

If I rephrase my question as: How can you 'navigate' between multiple nested fo开发者_Go百科rs ? This approach would be the 'recommended' way ? because this is what it says in SCJP Book. If not .. would this mean that Katherine Sierra and Bert Bates are wrong ?

Edited2:

Why is continue label; discouraged ? I want an answer of the concepts or inside workings of OOP or Java, what might go wrong ..


The answer is: it depends. If you find yourself using continue a lot then it might be a sign that your code needs a refactor. However, in the scenario you've given it seems like an OK place to use it.


I would refactor to make it more readable.

Example:

if (!checkWhatever()) {
    // some code I don't want to execute if whatever is true
}
boolean checkWhatever() {
    for (bla bla) {
       for (bla bla) {
          if (whatever) return false;
       }
    }
    return true;
}


I would say its discouraged. It still has valid uses where alternatives are more complex or error prone (i.e. not an improvement)


With reference to your Edit 2, it is always going to look a bit iffy because it violates an older programming orthodoxy than OO: 'structured programming'. It smacks of goto as well, and all good programmers know they need to go to confession if they let a goto into their code.

There could be some concern that it might make it harder for a compiler to analyse the control flow of a function, but it is the sort of tool that typically gets used for efficiency reasons. For instance, the Apache implementation of java.lang.String uses it in this function that is at least intended to be an optimisation:

/*
 * An implementation of a String.indexOf that is supposed to perform
 * substantially better than the default algorithm if the "needle" (the
 * subString being searched for) is a constant string.
 *
 * For example, a JIT, upon encountering a call to String.indexOf(String),
 * where the needle is a constant string, may compute the values cache, md2
 * and lastChar, and change the call to the following method.
 */
@SuppressWarnings("unused")
private static int indexOf(String haystackString, String needleString,
        int cache, int md2, char lastChar) {
    char[] haystack = haystackString.value;
    int haystackOffset = haystackString.offset;
    int haystackLength = haystackString.count;
    char[] needle = needleString.value;
    int needleOffset = needleString.offset;
    int needleLength = needleString.count;
    int needleLengthMinus1 = needleLength - 1;
    int haystackEnd = haystackOffset + haystackLength;
    // Label: <----------------------------------------
    outer_loop: for (int i = haystackOffset + needleLengthMinus1; i < haystackEnd;) {
        if (lastChar == haystack[i]) {
            for (int j = 0; j < needleLengthMinus1; ++j) {
                if (needle[j + needleOffset] != haystack[i + j
                        - needleLengthMinus1]) {
                    int skip = 1;
                    if ((cache & (1 << haystack[i])) == 0) {
                        skip += j;
                    }
                    i += Math.max(md2, skip);
                    // Continue to label:  <---------------------------
                    continue outer_loop;
                }
            }
            return i - needleLengthMinus1 - haystackOffset;
        }

        if ((cache & (1 << haystack[i])) == 0) {
            i += needleLengthMinus1;
        }
        i++;
    }
    return -1;
}


Refactor to make it more readable, by placing the inner loop in its own method:

for (bla bla) {   
  DoStuff();
}
void DoStuff() {
  for (bla bla) {
    if (whatever) return;
  }
  // some code to execute when whatever is false.
}

The principle: If a method becomes complex enough to require LABELING a block, consider refactoring part of that method into a separate method, such that no label is needed.

Similarly, it is unwise to make methods that are THREE loops deep. Unless the loops are very simple. Even if no labels are needed. Make sure the outermost flow construct (a loop, or an if/else, or a switch) is easy to read, by hiding complexity inside other methods. Even if those methods are only called from one place.


Use a boolean called 'success' or something like that. It's much easier to read and to follow the flow. Gotos should only be used for error handling.

boolean success = true;
for(int outer = 0; (outer <= outerLimit) && sucess; outer++)
{
    for(int inner = 0; (inner <= innerLimit) && success; inner++)
    {
        if( !doInnerStuff() )
        {
            success = false;
        }
    }

    if( success )
    {
        success = doOuterStuff();
    }
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号