When the complexity of the logic becomes unwieldy then using an unbounded loop with mid-loop breaks for flow control does actually make the mostsome sense. I have a project with some code which looks like the following. (Notice the exception at the end of the loop.)
 So the exception is now thrown in a helper method. Also it has quite a lot of if ... else nesting. I'm not satisfied with this approach. Therefore I think the first pattern
However, there is besta third approach, which is probably most acceptable. Put the logic into a method, and just return when done. So if we take the first approach above and slightly refactor it, we get this:
void method()
{
    myMethod(someBool);
    progressOntoOtherThings();
}
void myMethod()
{
    if (someBool) {
        someOtherBool = doSomeWork();
        if (someOtherBool) {
            doFinalWork();
            return;
        }
        someOtherBool2 = doSomeWork2();
        if (someOtherBool2) {
            doFinalWork2();
            return;
        }
        someOtherBool3 = doSomeWork3();
        if (someOtherBool3) {
            doFinalWork3();
            return;
        }
    }
    bitOfData = getTheData();
    throw new SomeException("Unable to do something for some reason.", bitOfData);
}