简体   繁体   中英

Try Catch Final - final always has null in variable

I am currently facing an issue with my code and I can't figure out why this statement is evaluating as it is. This is the first time I am using a finally block, so it may be that there is some fundamental behaviour I haven't understood.

What this method does is it gets a json document from an api and stores said document as this.thisPage . Then another method sliceItem does the splitting of the results field into an array of json objects.

A MalformedJsonException is thrown whenever the API returns a json that has bad fields (ex. String fields being stored as int, or int as double etc.). This is tried 10 times (handled by failsafeget) and if it failed 10 times, MalformedJsonException (RuntimeException) is thrown. What I would like slicePage to do in that case is get the next page instead of continuing with this page. To simplify this - each page has 100 entries; if the offset 3500 is broken, we want to get offset 3600.

The issue that I am facing currently is that resp always evaluates to null in the final block. I cannot understand why this is the case, since the try block can return something other than null (JSONObject type).

Any help would be greatly appreciated and if you need more information/code, I am willing to provide it.

public synchronized void slicePage(){
    JSONObject resp=null; // otherwise java complains that not initialised
    ApiClient apiClient = new ApiClient();
    RestEndPoint pageUrl;
    while (true) {
        pageUrl = getNextPageEndPoint();
        if(pageUrl == null) {
            throw new IllegalStateException("We have reached the end and the code isn't designed to handle the end here"); // we have reached the end
        }
        currentPageNumber++;
        try {
            resp = apiClient.failSafeGet(pageUrl, getRetryCount());
            break;
        }
        catch (MalformedJsonException e) {
            logger.info(String.format("The json was still broken after %d retries. Skipping this page and notifying listeners", getRetryCount()));
            for (Consumer<Integer> consumer: onSkipListenerList) {
                consumer.accept(batchSize); // inform each listener that we are skipping this many entries
            }
        }
        finally { // We need to set the next page end point no matter the outcome of the try catch. N.B. this gets executed even if there is a break
            if(resp == null) {
                // no next possible
                setNextPageEndPoint(null);   // don't consider next; we reached the max
                this.thisPage = null;
            } else {
                if(currentPageNumber > maxPages - 1) {
                    // because a request has been made already, so reduce by 1
                    setNextPageEndPoint(null); // don't consider next; we reached the max
                } else {
                    // else consider next page
                    setNextPageEndPoint(constructNextPageEndPoint(pageUrl, resp));
                }
                this.thisPage = this.parseResult(resp);

                setTotalCount(resp.getInt("totalResults"));
            }
        }
    }
}

EDIT I forgot to mention, that when I said it always evaluates to null, I meant that my IDE - Intellij IDEA, is warning me that the if condition always evaluates to null. The following is the help that shows up in Intellij (with Ctrl-F1).

 Condition 'resp == null' is always 'true' less... (Ctrl+F1) 
 This inspection analyzes method control and data flow to report possible conditions that are always true or false, expressions whose value is statically proven to be constant, and situations that can lead to nullability contract violations.
 Variables, method parameters and return values marked as @Nullable or @NotNull are treated as nullable (or not-null, respectively) and used during the analysis to check nullability contracts, e.g. report possible NullPointerException errors.
More complex contracts can be defined using @Contract annotation, for example:
@Contract("_, null -> null") — method returns null if its second argument is null @Contract("_, null -> null; _, !null -> !null") — method returns null if its second argument is null and not-null otherwise @Contract("true -> fail") — a typical assertFalse method which throws an exception if true is passed to it 
The inspection can be configured to use custom @Nullable
@NotNull annotations (by default the ones from annotations.jar will be used)

EDIT 2 As it turns out, the code analysis is wrong, the value is non-null once run. Thank you everyone (including commentators) for sharing your insights and advice. Ultimately I inserted a logger.info with the value before the condition and everything seemed to work. The reason it seemed to stop working is because the graph server was running into timeouts.

This is normal behaviour. This call

apiClient.failSafeGet(pageUrl, getRetryCount());

throws the exception, so the value assignment to resp is never completed so in the finally block the value is null. So, either you method is always throwing an exception, or, if not, it is returning null at some point.

In your code:

try {
            resp = apiClient.failSafeGet(pageUrl, getRetryCount());
            break;
        }
        catch (MalformedJsonException e) {
            logger.info(String.format("The json was still broken after %d retries. Skipping this page and notifying listeners", getRetryCount()));
            for (Consumer<Integer> consumer: onSkipListenerList) {
                consumer.accept(batchSize); // inform each listener that we are skipping this many entries
            }
        }
        finally {.....

If resp = apiClient.failSafeGet(pageUrl, getRetryCount()); throws an exception, resp will be always null, because the program failed before assing the instance to resp.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM