Search code examples
javaasynchronouslambdahttpclientnetty

Why `break label` cannot be used inside lambda expression? Any workaround?


I am trying to implement a retry mechanism for HTTP request with a HTTPClient library. For the retry mechanism, I have a list of website to try and I will try each website for retries times. The process ends when I receive a status 200 from any of the requests.

My idea is to use a boolean requestSuccess and a label requestLabel. I will set requestSuccess = true and break the requestLabel when I receive a status 200. However, variable must be (effectively) final and break label is not available inside lambda expression.

Is there any workaround to implement such retry mechanism?

boolean requestSuccess = false;

requestLabel: 
for(String site: sites) {
    for(int i = 0; i < retries; i++) {
        client.request(site, data, requestOptions, (err, res, content) -> {
            if(err == null) {
                requestSuccess = true;
                break requestLabel;
            } else {
                log(...);
            }
        })
    }
}

if(!requestSuccess) {
    log("request failed");
}


One possible answer

Inspired by a submitted then deleted answer, I can use a wrapped-class-like solution. I think it would work, but it seems dirty?

boolean[] requestSuccess = new boolean[1];

requestLabel:
for(String site: sites) {
    for(int i = 0; i < retries; i++) {
        if(requestSuccess[0] == true) {
            break requestLabel;
        }

        client.request(site, data, requestOptions, (err, res, content) -> {
            if(err == null) {
                requestSuccess[0] = true;
            } else {
                log(...);
            }
        })
    }
}

if(!requestSuccess) {
    log("request failed");
}

Solution

  • A lambda gets turned into it's own class under the hood. It would be as if you have two classes as far as the java interpreter is concerned.

    class Main {
        public void runstuff() {
            labelX:
            for(...) {
                client.request(new Main$Foo().xyz(.....));
            }
        }
    
        class Foo {
             public xyz(....) {
                 break labelX; // There is no labelX to break to here in Foo.xyz
             }
        }
    }