do loop bug?

Discussion in 'Java' started by emrefan, Aug 10, 2006.

  1. emrefan

    emrefan Guest

    Does this program below indicate to you that there's a bug in java's do
    loop. Or is it just one of those many traps that I've fallen into and
    I've only got myself to blame? I was expecting the two loops would
    behave much the same. Have I been bitten by the optimizer?

    public class DoLoopBug {
    public static void main( String[] args ) {
    int retryCnt = 0;
    doLoop1: do {
    try {
    if (retryCnt < 3)
    throw new java.net.ConnectException();
    break;
    }
    catch (Exception e) {
    System.out.println( "caught exception; retryCnt=" +
    retryCnt );
    if (++retryCnt < 20)
    continue doLoop1;
    }
    } while (false);

    System.out.println( "after doLoop1, retryCnt = " + retryCnt +
    "\n" );

    retryCnt = 0;

    doLoop2: do {
    try {
    if (retryCnt < 3)
    throw new java.net.ConnectException();
    break;
    }
    catch (Exception e) {
    System.out.println( "caught exception; retryCnt=" +
    retryCnt );
    if (++retryCnt < 20)
    continue doLoop2;
    }
    } while (true); // Here's difference from DoLoop1

    System.out.println( "after doLoop2, retryCnt = " + retryCnt );
    }
    }
    emrefan, Aug 10, 2006
    #1
    1. Advertising

  2. emrefan wrote:
    > Does this program below indicate to you that there's a bug in java's do
    > loop. Or is it just one of those many traps that I've fallen into and
    > I've only got myself to blame? I was expecting the two loops would
    > behave much the same. Have I been bitten by the optimizer?
    >
    > public class DoLoopBug {
    > public static void main( String[] args ) {
    > int retryCnt = 0;
    > doLoop1: do {
    > try {
    > if (retryCnt < 3)
    > throw new java.net.ConnectException();
    > break;
    > }
    > catch (Exception e) {
    > System.out.println( "caught exception; retryCnt=" +
    > retryCnt );
    > if (++retryCnt < 20)
    > continue doLoop1;
    > }
    > } while (false);
    >
    > System.out.println( "after doLoop1, retryCnt = " + retryCnt +
    > "\n" );
    >
    > retryCnt = 0;
    >
    > doLoop2: do {
    > try {
    > if (retryCnt < 3)
    > throw new java.net.ConnectException();
    > break;
    > }
    > catch (Exception e) {
    > System.out.println( "caught exception; retryCnt=" +
    > retryCnt );
    > if (++retryCnt < 20)
    > continue doLoop2;
    > }
    > } while (true); // Here's difference from DoLoop1
    >
    > System.out.println( "after doLoop2, retryCnt = " + retryCnt );
    > }
    > }
    >



    The results I get are:

    caught exception; retryCnt=0
    after doLoop1, retryCnt = 1

    caught exception; retryCnt=0
    caught exception; retryCnt=1
    caught exception; retryCnt=2
    after doLoop2, retryCnt = 3

    which is what I expected.

    Each continue effectively jumps to its loop's while expression
    evaluation. For the first loop, the expression evaluates to false, so it
    falls through first time.

    For the second loop, the while expression evaluates to true, so it does
    another iteration. That goes on until retryCnt reaches 3, and the break
    is executed instead of the throw leading to a continue.

    If this does not answer your question, perhaps you could explain why you
    expected the two loops to behave the same?

    Patricia
    Patricia Shanahan, Aug 10, 2006
    #2
    1. Advertising

  3. "Patricia Shanahan" <> wrote in message
    news:65wCg.6665$...
    > emrefan wrote:
    >> Does this program below indicate to you that there's a bug in java's do
    >> loop. Or is it just one of those many traps that I've fallen into and
    >> I've only got myself to blame? I was expecting the two loops would
    >> behave much the same. Have I been bitten by the optimizer?
    >>
    >> public class DoLoopBug {
    >> public static void main( String[] args ) {
    >> int retryCnt = 0;
    >> doLoop1: do {
    >> try {
    >> if (retryCnt < 3)
    >> throw new java.net.ConnectException();
    >> break;
    >> }
    >> catch (Exception e) {
    >> System.out.println( "caught exception; retryCnt=" +
    >> retryCnt );
    >> if (++retryCnt < 20)
    >> continue doLoop1;
    >> }
    >> } while (false);
    >>
    >> System.out.println( "after doLoop1, retryCnt = " + retryCnt +
    >> "\n" );
    >>
    >> retryCnt = 0;
    >>
    >> doLoop2: do {
    >> try {
    >> if (retryCnt < 3)
    >> throw new java.net.ConnectException();
    >> break;
    >> }
    >> catch (Exception e) {
    >> System.out.println( "caught exception; retryCnt=" +
    >> retryCnt );
    >> if (++retryCnt < 20)
    >> continue doLoop2;
    >> }
    >> } while (true); // Here's difference from DoLoop1
    >>
    >> System.out.println( "after doLoop2, retryCnt = " + retryCnt );
    >> }
    >> }
    >>

    >
    >
    > The results I get are:
    >
    > caught exception; retryCnt=0
    > after doLoop1, retryCnt = 1
    >
    > caught exception; retryCnt=0
    > caught exception; retryCnt=1
    > caught exception; retryCnt=2
    > after doLoop2, retryCnt = 3
    >
    > which is what I expected.
    >
    > Each continue effectively jumps to its loop's while expression
    > evaluation.


    And both "continue"s are unnecessary, since evaluating the "while" is the
    next thing to be done anyway, making mw wonder what the intention of the
    code is.
    Mike Schilling, Aug 10, 2006
    #3
  4. Mike Schilling wrote:
    > "Patricia Shanahan" <> wrote in message
    > news:65wCg.6665$...

    ....
    >> Each continue effectively jumps to its loop's while expression
    >> evaluation.

    >
    > And both "continue"s are unnecessary, since evaluating the "while" is the
    > next thing to be done anyway, making mw wonder what the intention of the
    > code is.
    >
    >


    I assumed it was an artificial test case, stripped down from a larger
    program. I THINK maybe the OP expected the continue to unconditionally
    go on to another iteration, regardless of the while. That would not be
    equivalent to falling through to the while.

    Patricia
    Patricia Shanahan, Aug 10, 2006
    #4
  5. emrefan

    Thea Guest

    They both are right.
    And... one advice:
    *Never ever* use exceptions to control normal program flow.
    They serve to handle (as name indicates) exceptional situations while
    program execution.
    This is their purpose. Exception may mean from "this stupid user
    entered some text again when was asked to give a numer" up to
    "earthquake on the other end of the world destroyed server" ;) , but
    it's always something unusual. Exception means that something has gone
    wrong.
    Next thing: catch exactly exception that is thrown.
    If you throw ConnectException, catch this particular exception. This
    way you may get some more useful info.
    Also: continue (label).
    In this code labels are not necessary because (as said before) they
    cause jump to while statement in loop being executed. They would be
    useful if you wanted to jump somewhere else. But I *strongy recommend*
    *not* to do such jumps. They introduce lots of confusion and are likely
    to cause a lots of bugs that will be diffult to debug because of hard
    to predict program's behaviour. Whenever you want to make such jump,
    think twice is there is really no other way.
    Try to keep your code as short and simple as possible.
    That's my advice. Take it or leave it - it's up to you.
    Thea

    Mike Schilling napisal(a):
    > "Patricia Shanahan" <> wrote in message
    > news:65wCg.6665$...
    > > emrefan wrote:
    > >> Does this program below indicate to you that there's a bug in java's do
    > >> loop. Or is it just one of those many traps that I've fallen into and
    > >> I've only got myself to blame? I was expecting the two loops would
    > >> behave much the same. Have I been bitten by the optimizer?
    > >>
    > >> public class DoLoopBug {
    > >> public static void main( String[] args ) {
    > >> int retryCnt = 0;
    > >> doLoop1: do {
    > >> try {
    > >> if (retryCnt < 3)
    > >> throw new java.net.ConnectException();
    > >> break;
    > >> }
    > >> catch (Exception e) {
    > >> System.out.println( "caught exception; retryCnt=" +
    > >> retryCnt );
    > >> if (++retryCnt < 20)
    > >> continue doLoop1;
    > >> }
    > >> } while (false);
    > >>
    > >> System.out.println( "after doLoop1, retryCnt = " + retryCnt +
    > >> "\n" );
    > >>
    > >> retryCnt = 0;
    > >>
    > >> doLoop2: do {
    > >> try {
    > >> if (retryCnt < 3)
    > >> throw new java.net.ConnectException();
    > >> break;
    > >> }
    > >> catch (Exception e) {
    > >> System.out.println( "caught exception; retryCnt=" +
    > >> retryCnt );
    > >> if (++retryCnt < 20)
    > >> continue doLoop2;
    > >> }
    > >> } while (true); // Here's difference from DoLoop1
    > >>
    > >> System.out.println( "after doLoop2, retryCnt = " + retryCnt );
    > >> }
    > >> }
    > >>

    > >
    > >
    > > The results I get are:
    > >
    > > caught exception; retryCnt=0
    > > after doLoop1, retryCnt = 1
    > >
    > > caught exception; retryCnt=0
    > > caught exception; retryCnt=1
    > > caught exception; retryCnt=2
    > > after doLoop2, retryCnt = 3
    > >
    > > which is what I expected.
    > >
    > > Each continue effectively jumps to its loop's while expression
    > > evaluation.

    >
    > And both "continue"s are unnecessary, since evaluating the "while" is the
    > next thing to be done anyway, making mw wonder what the intention of the
    > code is.
    Thea, Aug 10, 2006
    #5
  6. "Patricia Shanahan" <> wrote in message
    news:9uACg.2388$...
    > Mike Schilling wrote:
    >> "Patricia Shanahan" <> wrote in message
    >> news:65wCg.6665$...

    > ...
    >>> Each continue effectively jumps to its loop's while expression
    >>> evaluation.

    >>
    >> And both "continue"s are unnecessary, since evaluating the "while" is the
    >> next thing to be done anyway, making mw wonder what the intention of the
    >> code is.

    >
    > I assumed it was an artificial test case, stripped down from a larger
    > program. I THINK maybe the OP expected the continue to unconditionally
    > go on to another iteration, regardless of the while. That would not be
    > equivalent to falling through to the while.


    I'm not sure why they were there, which is why I thought it worth pointing
    out that they did nothing.
    Mike Schilling, Aug 10, 2006
    #6
  7. emrefan

    emrefan Guest

    > The results I get are:
    >
    > caught exception; retryCnt=0
    > after doLoop1, retryCnt = 1
    >
    > caught exception; retryCnt=0
    > caught exception; retryCnt=1
    > caught exception; retryCnt=2
    > after doLoop2, retryCnt = 3
    >
    > which is what I expected.
    >
    > Each continue effectively jumps to its loop's while expression
    > evaluation. For the first loop, the expression evaluates to false, so it
    > falls through first time.


    Thank you for responding.

    This surprises me! I was expecting the continue to restart the loop
    without even looking at the while expression. I need to brush up on
    java basics <blush>. Maybe other languages have poisoned me.

    > For the second loop, the while expression evaluates to true, so it does
    > another iteration. That goes on until retryCnt reaches 3, and the break
    > is executed instead of the throw leading to a continue.
    >
    > If this does not answer your question, perhaps you could explain why you
    > expected the two loops to behave the same?


    Well, I used such a strange construct in the real thing because I
    wanted to retry some servlet accessing operation if a
    java.net.ConnectException happened. And indeed this exception happened
    quite often for a particular customer who was running the relevant
    applet. It did not happen each and every time for this customer and
    other customers were not suffering the same problem - at least not
    frequently enough for them to raise an issue with us.

    You explanation is perfectly clear to me. But the "continue to the
    while expression" bit trapped me up.
    emrefan, Aug 10, 2006
    #7
  8. emrefan

    emrefan Guest

    Patricia Shanahan wrote:
    > Mike Schilling wrote:
    > > "Patricia Shanahan" <> wrote in message
    > > news:65wCg.6665$...

    > ...
    > >> Each continue effectively jumps to its loop's while expression
    > >> evaluation.

    > >
    > > And both "continue"s are unnecessary, since evaluating the "while" is the
    > > next thing to be done anyway, making mw wonder what the intention of the
    > > code is.

    >
    > I assumed it was an artificial test case, stripped down from a larger
    > program. I THINK maybe the OP expected the continue to unconditionally
    > go on to another iteration, regardless of the while. That would not be
    > equivalent to falling through to the while.


    You are right, what I posted was just a test program to illustrate a
    point. And you guessed right, I did expect the continue to
    unconditionally go on to another iteration.
    Searched the net for a replacement goto construct in java and I found
    that "There: do { ... continue There } while (false)" bit of code and
    promptly used it without much thought. First timed I used the "do
    loop", I admit.
    emrefan, Aug 10, 2006
    #8
  9. emrefan

    emrefan Guest

    Mike Schilling wrote:
    > "Patricia Shanahan" <> wrote in message
    > news:9uACg.2388$...
    > > Mike Schilling wrote:
    > >> "Patricia Shanahan" <> wrote in message
    > >> news:65wCg.6665$...

    > > ...
    > >>> Each continue effectively jumps to its loop's while expression
    > >>> evaluation.
    > >>
    > >> And both "continue"s are unnecessary, since evaluating the "while" is the
    > >> next thing to be done anyway, making mw wonder what the intention of the
    > >> code is.

    > >
    > > I assumed it was an artificial test case, stripped down from a larger
    > > program. I THINK maybe the OP expected the continue to unconditionally
    > > go on to another iteration, regardless of the while. That would not be
    > > equivalent to falling through to the while.

    >
    > I'm not sure why they were there, which is why I thought it worth pointing
    > out that they did nothing.


    I used such a do loop construct because that I was what I found while
    googling. Didn't realize I could do without the label. Now that I've
    given it a thought, I guess maybe some people want to use a label to
    show what is being continued. I personally would have used a comment
    after the "continue" to get the same readability result if I had known
    that the label wasn't necessary.
    emrefan, Aug 10, 2006
    #9
  10. "emrefan" <> wrote in message
    news:...
    >
    > Well, I used such a strange construct in the real thing because I
    > wanted to retry some servlet accessing operation if a
    > java.net.ConnectException happened. And indeed this exception happened
    > quite often for a particular customer who was running the relevant
    > applet. It did not happen each and every time for this customer and
    > other customers were not suffering the same problem - at least not
    > frequently enough for them to raise an issue with us.
    >
    > You explanation is perfectly clear to me. But the "continue to the
    > while expression" bit trapped me up.


    If you're loooking for a construct that says "retry if an exception
    happened", here's a thought:

    boolean done = false;
    while (!done)
    {
    try
    {
    ...
    done = true;
    }
    catch (Exception ex)
    {
    ...
    }
    }

    This will exit the loop only if the code in the try block throws no
    exceptions. Of course, you can tinker with it to limit the number of
    retries, say

    boolean done = false;
    int retryCount = 0;
    while (!done && retryCount < 3)
    {
    try
    {
    ...
    done = true;
    }
    catch (Exception ex)
    {
    ...
    retryCount++;
    }
    }
    Mike Schilling, Aug 10, 2006
    #10
  11. emrefan

    emrefan Guest

    Thea wrote:
    > They both are right.
    > And... one advice:
    > *Never ever* use exceptions to control normal program flow.


    Point taken. Didn't do that in a real program and will keep from doing
    it.

    > Next thing: catch exactly exception that is thrown.


    What if a class of exception are to be caught and there's still a need
    to be specific about a single particular one within this class? I
    think I'd code thusly if the code to handle this class of exceptions
    are much the same except for a tiny variation for "that special one".

    > Also: continue (label).
    > In this code labels are not necessary because (as said before) they
    > cause jump to while statement in loop being executed. They would be
    > useful if you wanted to jump somewhere else. But I *strongy recommend*
    > *not* to do such jumps. They introduce lots of confusion and are likely
    > to cause a lots of bugs that will be diffult to debug because of hard
    > to predict program's behaviour. Whenever you want to make such jump,
    > think twice is there is really no other way.
    > Try to keep your code as short and simple as possible.
    > That's my advice. Take it or leave it - it's up to you.


    Right, avoid goto at all costs? :) Think I will still use it sparsingly
    where the identation entailed by the orthodox way gets too much to be
    beared.
    emrefan, Aug 10, 2006
    #11
  12. emrefan

    emrefan Guest

    Thea wrote:
    > They both are right.
    > And... one advice:
    > *Never ever* use exceptions to control normal program flow.


    Point taken. Didn't do that in a real program and will keep from doing
    it.

    > Next thing: catch exactly exception that is thrown.


    What if a class of exception are to be caught and there's still a need
    to be specific about a single particular one within this class? I
    think I'd code thusly if the code to handle this class of exceptions
    are much the same except for a tiny variation for "that special one".

    > Also: continue (label).
    > In this code labels are not necessary because (as said before) they
    > cause jump to while statement in loop being executed. They would be
    > useful if you wanted to jump somewhere else. But I *strongy recommend*
    > *not* to do such jumps. They introduce lots of confusion and are likely
    > to cause a lots of bugs that will be diffult to debug because of hard
    > to predict program's behaviour. Whenever you want to make such jump,
    > think twice is there is really no other way.
    > Try to keep your code as short and simple as possible.
    > That's my advice. Take it or leave it - it's up to you.


    Right, avoid goto at all costs? :) Think I will still use it sparsingly
    where the identation entailed by the orthodox way gets too much to be
    beared.
    emrefan, Aug 10, 2006
    #12
  13. emrefan wrote:
    > Thea wrote:
    >> They both are right.
    >> And... one advice:
    >> *Never ever* use exceptions to control normal program flow.

    >
    > Point taken. Didn't do that in a real program and will keep from doing
    > it.
    >
    >> Next thing: catch exactly exception that is thrown.

    >
    > What if a class of exception are to be caught and there's still a need
    > to be specific about a single particular one within this class? I
    > think I'd code thusly if the code to handle this class of exceptions
    > are much the same except for a tiny variation for "that special one".


    Two points:

    1. The first applicable cache block gets executed.

    catch(EOFException e){
    // block 1
    }
    catch(IOException e){
    // block 2
    }

    runs block 1 for an EOFException, and block 2 for any IOException that
    is not an EOFException.

    2. If you have common code between two catch blocks you should do
    exactly what you should do if you have common code between any two
    related blocks in the program, see if you can make it into a method.


    >
    >> Also: continue (label).
    >> In this code labels are not necessary because (as said before) they
    >> cause jump to while statement in loop being executed. They would be
    >> useful if you wanted to jump somewhere else. But I *strongy recommend*
    >> *not* to do such jumps. They introduce lots of confusion and are likely
    >> to cause a lots of bugs that will be diffult to debug because of hard
    >> to predict program's behaviour. Whenever you want to make such jump,
    >> think twice is there is really no other way.
    >> Try to keep your code as short and simple as possible.
    >> That's my advice. Take it or leave it - it's up to you.

    >
    > Right, avoid goto at all costs? :) Think I will still use it sparsingly
    > where the identation entailed by the orthodox way gets too much to be
    > beared.
    >


    Over-deep indentation in Java is usually a sign of too much happening in
    one method, and a need to refactor.

    I don't believe in "avoid goto at all costs". In the decade that I spent
    programming mainly in C, I did write a couple of them. However, they
    were substitutes for try-finally. So far, I have not missed goto in Java.

    I do generally agree with the ideas in Dijkstra's classic "Go To
    Statement Considered Harmful" letter, http://www.acm.org/classics/oct95/

    Patricia
    Patricia Shanahan, Aug 10, 2006
    #13
  14. "Patricia Shanahan" <> wrote in message
    news:tKGCg.2032$...

    >
    > 1. The first applicable cache block gets executed.


    "catch block", of course.

    >
    > catch(EOFException e){
    > // block 1
    > }
    > catch(IOException e){
    > // block 2
    > }
    >
    > runs block 1 for an EOFException, and block 2 for any IOException that
    > is not an EOFException.
    Mike Schilling, Aug 10, 2006
    #14
  15. Mike Schilling wrote:
    > "Patricia Shanahan" <> wrote in message
    > news:tKGCg.2032$...
    >
    >> 1. The first applicable cache block gets executed.

    >
    > "catch block", of course.


    Yes, thanks for the early-morning-typo correction.

    >
    >> catch(EOFException e){
    >> // block 1
    >> }
    >> catch(IOException e){
    >> // block 2
    >> }
    >>
    >> runs block 1 for an EOFException, and block 2 for any IOException that
    >> is not an EOFException.

    >
    >
    Patricia Shanahan, Aug 10, 2006
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?VGltOjouLg==?=

    Loop the loop...

    =?Utf-8?B?VGltOjouLg==?=, Feb 16, 2005, in forum: ASP .Net
    Replies:
    2
    Views:
    1,369
    Karl Seguin
    Feb 16, 2005
  2. Steven

    while loop in a while loop

    Steven, Mar 24, 2005, in forum: Java
    Replies:
    5
    Views:
    2,210
    Tim Slattery
    Mar 30, 2005
  3. -
    Replies:
    12
    Views:
    675
    Remon van Vliet
    Jun 15, 2005
  4. Byte
    Replies:
    4
    Views:
    400
  5. Isaac Won
    Replies:
    9
    Views:
    348
    Ulrich Eckhardt
    Mar 4, 2013
Loading...

Share This Page