Java try with resources中出现死代码警告,但在翻译后的try catch finally中没有

Java try with resources中出现死代码警告,但在翻译后的try catch finally中没有,java,eclipse,try-with-resources,Java,Eclipse,Try With Resources,下面的代码使用Java8中引入的构造。occasionalythrow()方法声明抛出一个OccasionalException,资源的close()方法抛出一个CloseException。Eclipse(版本:Neon Release(4.6.0),构建id:20160613-1800)在标有//dead code的行上添加了一条警告,指出分支是死代码。Eclipse隐式地确认标有//alive code的行不是死代码 Object tryWithResources() throws Occ

下面的代码使用Java8中引入的构造。occasionalythrow()方法声明抛出一个OccasionalException资源的close()方法抛出一个CloseException。Eclipse(版本:Neon Release(4.6.0),构建id:20160613-1800)在标有//dead code的行上添加了一条警告,指出分支是死代码。Eclipse隐式地确认标有//alive 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;
}
我对此感到困惑。如果occasionallyThrow()抛出其OccasionalException,则带有资源的
try
-应将其捕获为主要异常,然后尝试关闭资源。如果关闭资源会抛出一个CloseException,那么它将在OccasionalException下被抑制,因此不会有要捕获的CloseException。因此,只有当try中的块成功完成时,才应该有CloseException进行捕获,这意味着value不为空。所以看起来“死代码”实际上是活的,“活代码”实际上是死的。我不确定编译器在这里应该识别什么,但至少,这里的“死代码”不应该被称为死代码

更复杂的是,未使用try with resources表单的翻译表单根本不会标记任何死代码警告。(我相当有信心,我得到了正确的翻译,基于,但我不会完全感到惊讶,如果有错误在这里…)

我是否遗漏了一些东西,使if-else中的任何一个分支在其中一个分支中死亡,而在另一个分支中不死亡

完整代码 下面是完整的代码,其中包含辅助异常类型、资源类和顶级类的定义

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;
    }
}
对评论的答复 建议在设置值以更改Eclipse的代码分析后使用资源的解决方法。但这不起作用。使用资源后(例如,通过打印),Luna和Neon中仍然存在死代码警告:


由于某种原因,静态代码分析器认为资源将在try声明之后立即关闭,而根据教程,资源将在语句之后关闭

try with resources语句确保在语句末尾关闭每个资源

因此,例如,如果您在值为(下面的代码)之后更改代码以使用资源,它不会警告您死代码(但是在EclipseLuna上测试)

更新

这是我在设置值后使用resource(在本例中为reader)测试的实际代码

        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{

            }
        }

这并不能回答为什么Eclipse会生成警告,或者是否应该生成警告的问题,但这是一种解决方法,至少暂时消除了警告。您可以调用另一个方法,使用被测试的值以及异常,从该方法测试对象是否为null,然后执行任何需要执行的操作,而不是将条件放入catch块中:

Object tryWithResources() throws OccasionalException {
    Object value = null;
    try (Resource resource = new Resource()) {
        occasionallyThrow();
        value = new Object();
        System.out.println(resource.toString());
    }
    catch (CloseException e) {
        catchBlock(value, e);  // call auxiliary method
    }
    return value;
}

void catchBlock(Object value, CloseException e) {
    if (value == null) {
        // then
    }
    else {
        // else
    }
}

也许是这样,尽管现在已经5年了……我不确定您是否能够捕获在关闭过程中抛出的异常,该异常是由try使用属于try块的catch块中的资源完成的。如果将CloseException更改为选中异常,会发生什么情况?如果您将捕获的内容另外移动到周围的尝试,会发生什么?@mm759首先回答中间的问题:CloseException是一个选中的异常。通过在这里将其定义为Exception的子类(而不是RuntimeException的子类),我确保了这一点。@mm759对于第一个问题,try with resources with a catch的行为由描述
try ResourceSpecification Block catch Finally
(这是我正在使用的(没有可选的Finally),被翻译为
try{try ResourceSpecification Block}catch Finally
。因此,当主体没有引发异常时,您可以捕捉隐式close引发的异常,所以(第二个问题)翻译已经“将捕获移动到周围的try[。]”可能还没有“确认”,但我个人可以确认它仍然发生在Eclipse4.5.2上。特别是标记为“死代码”的代码显然,当测试用例运行时会生成输出。同样,只有Eclipse生成警告-而不是JavaCus在设置值后使用资源并不会消除Eclipse中的死代码警告。我已经更新了问题,以显示警告仍然存在。那么它可能是特定于Eclipse Neon的。我在Eclipse Luna中尝试过它。不,我没有Luna和Eclipse中都出现了ied。警告都出现在这两个版本中。我再次更新了我的问题以显示这两个版本。很有趣。我还尝试了Neon。Neon中也出现了ied。我更新了答案以包含实际代码(我正在尝试使用BufferedReader,因为我没有您的代码)。好的,我想我知道这是什么。readLine()方法还抛出IOException,这可能就是为什么eclipse现在确信可以在设置值之后抛出异常。
        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{

            }
        }
Object tryWithResources() throws OccasionalException {
    Object value = null;
    try (Resource resource = new Resource()) {
        occasionallyThrow();
        value = new Object();
        System.out.println(resource.toString());
    }
    catch (CloseException e) {
        catchBlock(value, e);  // call auxiliary method
    }
    return value;
}

void catchBlock(Object value, CloseException e) {
    if (value == null) {
        // then
    }
    else {
        // else
    }
}