try-with-resources中的无效代码警告,但在经过翻译的try-catch-finally中则不存在 [英] Dead code warning in try-with-resources, but not in translated try-catch-finally

查看:119
本文介绍了try-with-resources中的无效代码警告,但在经过翻译的try-catch-finally中则不存在的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码使用 try -with-resources 构造. occasionallyThrow()方法声明为抛出 OccasionalException ,即 Resource close()方法引发 CloseException . Eclipse(版本:Neon发行版(4.6.0),内部版本号:20160613-1800)在标有//死代码的行上添加了一条警告,指出分支是死代码.隐含地,Eclipse确认标有//现行代码的行是 not 无效代码.

The following code uses the try-with-resources construction introduced in Java 8. The occasionallyThrow() method is declared to throw an OccasionalException, the Resource's close() method to throw a CloseException. Eclipse (Version: Neon Release (4.6.0), Build id: 20160613-1800) adds a warning on the line marked with // dead code that the branch is dead code. Implicitly, Eclipse affirms that the line marked with // alive 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;
}

对此我感到困惑.如果 occasionallyThrow()抛出其 OccasionalException ,则try -with-resources应该将其捕获为主要异常,然后尝试关闭资源.如果关闭资源引发 CloseException ,则会在 OccasionalException 下将其隐藏,因此不会捕获 CloseException .因此,只有 try 内的块成功完成时,才应该捕获 CloseException ,这意味着 value 不为空.因此,似乎无效代码"实际上还活着,而有效代码"实际上已经死了.我不确定在这里实际上预期编译器会识别什么,但是至少,似乎这里的死代码"应该被称为死的.

I'm confused by this. If occasionallyThrow() throws its OccasionalException, then the try-with-resources should catch that as the primary exception and then attempt to close the resource. If closing the resource throws a CloseException, then it will be suppressed under the OccasionalException, so there won't be the CloseException to catch. So, the only time there should be CloseException to catch is when the block within the try completed successfully which means that value is non-null. So it seems like the "dead code" is actually alive, and the "alive code" is actually dead. I'm not sure what a compiler is actually expected to recognize here, but at the very least, it seems like the "dead code" here should not be called dead.

使问题变得更复杂的是,未使用try-with-resources表单的转换后的表单根本不会被标记为任何无效代码警告. (我非常有信心,我根据

What makes this more complicated is that the translated form without using the try-with-resources form doesn't get marked with any dead code warnings at all. (I'm fairly confident that I got this translation right, based on 14.20.3.2. Extended try-with-resources, but I wouldn't be completely surprised if there's bug here…)

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;
}

我是否遗漏了一些东西,如果其中一个分支死于if-else,则不会在另一个分支死?

Am I missing something that would make either branch in the if-else dead in one of these, but not in the other?

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

Here's the full code with definitions of the auxiliary exception types, the Resource class, and the top-level class.

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;
    }
}

对评论的回应

Amin J的答案建议了一种解决方法,该方法是在设置 value 来更改Eclipse的值后使用资源代码分析.但是,这不起作用.在使用资源后(例如通过打印),Luna和Neon中仍然存在无效代码警告:

Responses to Comments

Amin J's answer suggested a workaround of using the resource after setting value to change Eclipse's code analysis. This doesn't work though. After using the resource, e.g., by printing it, the dead code warning is still present in both Luna and Neon:

推荐答案

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

This doesn't answer the question of why Eclipse is generating the warning that it is, or whether it should be or not, but this is a workaround that at least eliminates the warning for the time being. Rather than putting the conditional in the catch block, you can call another method with the value being tested as well as a the exception, and from that method test whether the object is null and then do whatever needs to be done:

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
    }
}

这篇关于try-with-resources中的无效代码警告,但在经过翻译的try-catch-finally中则不存在的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆