Java – dead code warning in try with resources, but not in try catch finally in translation

The following code uses the try - with - resources structure introduced in Java 8 Occasionally, the throw () method is declared to throw an occasionalexception, and the close () method of the resource throws a closeexception Eclipse (version: Neon release (4.6.0), build ID: 20160613-1800) adds a warning on the line marked with / / dead code, indicating that the branch is dead code Implicitly, eclipse confirms that the line marked / / active code is not dead code

Object tryWithResources() throws OccasionalException {
    Object value = null;
    try (Resource resource = new Resource()) {
        occasionallyThrow();
        value = new Object();
    }
    catch (CloseException e) {
        if (value == null) {
            // alive code
        }
        else {
            // dead code
        }
    }
    return value;
}

I'm confused If throw () accidentally throws its occasionalexception, try with resources should catch it as the main exception and try to close the resource If closing a resource throws a closeexception, it will be suppressed under occasionalexception, so closeexception will not be caught Therefore, the only closeexception that needs to be captured is when the block in the try completes successfully, which means that the value is non null So it seems that the "dead code" is actually alive, and the "living code" is actually dead I'm not sure what the compiler should actually recognize here, but at least the "dead code" here doesn't seem to be called dead

To complicate matters, translation forms that do not use the try with resources form are not marked with any dead code warnings at all (I am very confident that my translation is correct based on 14.20.3.2. Extended try with resources, but I won't be surprised if there are errors...)

Object expandedTry() throws OccasionalException {
    Object value = null;
    try {
        Resource resource = new Resource();
        Throwable $primary = null;
        try {
            occasionallyThrow();
            value = new Object();
        }
        catch (Throwable t) {
            $primary = t;
            throw t;
        }
        finally {
            if (resource != null) {
                if ($primary != null) {
                    try {
                        resource.close();
                    }
                    catch (Throwable $suppressed) {
                        $primary.addSuppressed($suppressed);
                    }
                }
                else {
                    resource.close();
                }
            }
        }
    }
    catch (CloseException e) {
        if (value == null) {
            // alive (not dead!)
        }
        else {
            // alive
        }
    }
    return value;
}

Did I miss something that would cause any branch of if else to die in one, not the other?

Complete code

This is the complete code that contains the definitions of auxiliary exception types, resource classes and top-level classes

public class TestTryWithResources {

    /** Exception thrown by Resource's close() method */
    @SuppressWarnings("serial")
    static class CloseException extends Exception {}

    /** AutoCloseable declared to throw a CloseException */ 
    static class Resource implements AutoCloseable {
        @Override
        public void close() throws CloseException {}
    }

    /** An occasionally thrown exception */
    @SuppressWarnings("serial")
    static class OccasionalException extends Exception {}

    /** Method declared to throw an occasional exception */
    void occasionallyThrow() throws OccasionalException {}

    /*
     * Method using try-with-resources.  Eclipse warns that the 
     * portion marked with "// dead code" is Dead code.
     */
    Object tryWithResources() throws OccasionalException {
        Object value = null;
        try (Resource resource = new Resource()) {
            occasionallyThrow();
            value = new Object();
        }
        catch (CloseException e) {
            if (value == null) {
                // alive code
            }
            else {
                // dead code
            }
        }
        return value;
    }

    /*
     * Method not using try-with-resources.  This is the translation
     * of the try-with-resources in tryWithResources,according to 
     * [14.20.3 try-with-resources][1].  Eclipse does not warn about 
     * any of the code being Dead code.
     * 
     * [1]: https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.20.3 
     */
    Object expandedTry() throws OccasionalException {
        Object value = null;
        try {
            Resource resource = new Resource();
            Throwable $primary = null;
            try {
                occasionallyThrow();
                value = new Object();
            }
            catch (Throwable t) {
                $primary = t;
                throw t;
            }
            finally {
                if (resource != null) {
                    if ($primary != null) {
                        try {
                            resource.close();
                        }
                        catch (Throwable $suppressed) {
                            $primary.addSuppressed($suppressed);
                        }
                    }
                    else {
                        resource.close();
                    }
                }
            }
        }
        catch (CloseException e) {
            if (value == null) {
                // alive
            }
            else {
                // alive
            }
        }
        return value;
    }
}

Respond to comments

Amin J's answer recommends using resources to change eclipse's code analysis after setting values But it doesn't work After using the resource, for example, by printing it, there are still dead code warnings in Luna and neon:

Solution

For some reason, the static code analyzer thinks that the resource will be closed immediately after the try declaration, while according to this tutorial, the resource will be closed after the statement

The try with resources statement ensures that each resource is closed at the end of the statement

So, for example, if you change the code to use the resource after the value is (code below), it will not warn you of dead code (but test on eclipse Luna)

Object tryWithResources() throws OccasionalException {
    Object value = null;
    try (Resource resource = new Resource()) {
        occasionallyThrow();
        value = new Object();
        resource.someMethod(); // using the resource,so eclipse thinks it's not closed yet (correctly)
    }
    catch (CloseException e) {
        if (value == null) {
            // alive code
        }
        else {
            // dead code
        }
    }
    return value;
}

UPDATE

This is the actual code I tested with the resource (reader in this case) after setting the value

Object val = null;

        try (BufferedReader reader = new BufferedReader(new FileReader("C:\\file.txt"))) {
            val = new Object();
            System.out.println("got here");
            reader.readLine();
        }
        catch(IOException e){
            System.out.println("io ex");
            if ( val == null){

            }
            else{

            }
        }
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>