避免在catch子句中实际/逻辑上无法访问的代码

时间:2014-01-31 03:45:13

标签: java exception try-catch unreachable-code

我有一个界面:

public interface FileRepository {
    String insert(File file) throws IOException;
    // other methods ...
}

我的insert(File file)实现使用本地(以避免并发问题)java.security.MessageDigester从其工厂方法抛出已检查的异常java.security.NoSuchAlgorithmException

public FileRepositoryImpl(String digestAlgo) throws NoSuchAlgorithmException {
    this.digestAlgo = digestAlgo;
    MessageDigest.getInstance(digestAlgo);
    }
@Override
public String insert(File file) throws IOException {
// initialize message digest
    MessageDigest messageDigest = null;
    try {
        messageDigest = MessageDigest.getInstance(digestAlgo);
    } catch (NoSuchAlgorithmException e) {
        LOGGER.fatal(MD_INIT_ERROR, e);
        return null;
}
    // other code ....
}
// other methods (may contain local MessageDigest)

我的做法:由于NoSuchAlgorithmException始终是一个致命错误(使模块完全不可用),我尝试在构造函数中初始化MessageDigest以测试参数digestAlgo,所以构造函数抛出异常,其他(早期)而不是insert(File)。另一个原因是界面不允许按定义抛出NoSuchAlgorithmException

我的问题:在我的实现中,代码

   } catch (NoSuchAlgorithmException e) {
        LOGGER.fatal(MD_INIT_ERROR, e);
        return null;
   }
永远不会达到

,所以我认为应该有更好的解决方案,这样可以避免(逻辑上和实际上)无法访问的代码。

欢迎任何解决方案/建议,谢谢。

编辑:

运行代码时,这不是一个真正的问题。但是在测试中,由于代码无法访问,加上一些“资源试用”,质量分析工具(声纳,pmd)将考虑代码“单元测试的分支覆盖率不足”,这是一个主要问题。分析报告,这就是为什么我要避免这段代码。

另一个问题是,在我的构造函数中测试MessageDigest.getInstance(digestAlgo);是一个好习惯吗?或者最好让insert(File)NoSuchAlgorithmException完全负责?

2 个答案:

答案 0 :(得分:1)

这堂课有太多了。如果它正如它的名字所暗示的那样,它的重点应放在存储文件上,但是在获取MessageDigest实例时显然存在很多不相关的活动 - 如果这个类有责任创建一种隧道(通过静态方法)依赖MessageDigest?依赖注入有很多选项,所有这些选项都可以让您卸载将对象配置到专用于此目的的框架(Spring,Guice,PicoContainer等)的职责。

我认为你在这里认识到这个问题,所以这是一个很好的开始。作为一项规则,你应该努力不抛出异常,通常对象构造函数是我最不喜欢的地方。如果您使用框架来帮助您配置对象,那么您在这里遇到的尴尬可能会完全消失。此外,不是一次而是两次你返回null - 它会让你在方法调用的另一端检查null,你真的想这样做吗?如果你考虑一下,我打赌你会想找到另一种方式(你还有其他选择)。

此外,您会发现使用专门的对象创建工厂(这是那些依赖注入框架)配置对象将帮助您更松散地将组件耦合在一起,这将促进测试组件的可能性与真正的依赖关系隔离 - 使用模拟进行测试。如果您可以在思考自己希望在执行其他任何操作之前编写的代码的单元测试的位置,那么您应该会看到更好的设计几乎在不知不觉中开始发生。 GOOS本书是一本很好的资源。祝福!

编辑:我误读了 - 看起来你只返回一次null,但那仍然是一次太多。 : - /

答案 1 :(得分:0)

我想我会更改构造函数以获取MessageDigest而不是算法名称,并让调用者处理异常。但这里还有另一个问题。将digester作为实例成员意味着该类不是线程安全的。