7

我在一本 C# 介绍性书中读到,如果您不知道如何处理异常,则不应捕获异常。想到用 Java 编程时的那一点建议,我有时发现我不知道如何处理异常,但我不得不捕捉它或“渗透它”以避免编译错误。我宁愿不要throws在调用树的整个过程中使用带有子句的混乱方法,所以我经常求助于将异常“转换”为 a RuntimeException,如下所示。将throws子句添加到许多方法中以处理没有真正“处理”(正确处理)的异常似乎冗长且分散注意力。以下是不好的风格,如果是这样,有什么更好的方法来处理这个问题?

try {
  thread.join();
}
catch (InterruptedException e) {
      Console.printwriter.format("%s\n", e.printStackTrace());
  throw new RuntimeException();
}

编辑:除了混乱之外,渗透异常还有另一个问题:在代码修订之后,您可能最终会遇到一些不必要的throws子句。我知道清除它们的唯一方法是反复试验:删除它们并查看编译器是否抱怨。显然,如果您想保持代码干净,这很烦人。

4

4 回答 4

5

Java 中已检查异常和未检查异常之间的划分有些争议

如果您控制界面,在签名中添加 throws 子句通常是最好的方法。

如果您处于无法处理异常的情况,但由于检查了异常签名而不允许让它冒泡,那么将异常包装到可以重新抛出的异常(通常是 RuntimeException)是常见的做法。

但是,在许多情况下,您希望使用另一个检查异常,例如 IOException 或 SQLException。但这并不总是一种选择。

但在您的示例中,将原始异常包含为“原因”:

 throw new RuntimeException(e);

这也可能消除对日志记录的需要(因为这也可以推迟到可以处理异常的人,并且所有信息仍然存在)。

于 2012-11-22T10:07:30.310 回答
1

如果您不知道如何处理异常,则不应捕获它。因此,您的方法现在将抛出一个异常,因此如果它不是运行时异常,它应该有一个 throws 子句。他们没有错。

于 2012-11-22T10:09:37.847 回答
1

良好的编程实践告诉你应该对调用者隐藏对象的内部状态,至​​少对我来说,这也包括异常。您应该看到该异常对您来说意味着什么,并向您的类的调用者返回一个表示该含义的异常。

如果框架已经提供了具有该含义的异常,例如 IllegalArgumentException,您应该实例化一个新对象,给它一个字符串,很好地描述发生的事情并封装发生的异常,类似于 new IllegalArgumentException("The argument X 无效,因为 ...", e); 如果框架对您的问题没有很好的描述性异常,您应该创建自己的一组异常。我通常为该项目/包创建一个通用异常(它将扩展 Exception 或 RuntimeException)并从中派生异常。例如,我最近创建了一个通用存储库项目,以便在我们的服务和应用程序模块中重用以访问数据库。因为我想从我用来访问数据库的东西中抽象出调用程序,即使是异常,我最终还是创建了一些异常来封装 JPA Hibernate 异常。我这里没有代码,但它类似于:

// implementation package
public abstract class GenericRepository<K, E extends<K>> implements IRepository<K, E>{

    //  constructors

    public final void add(E entity){
        // some code

        try{
            //  code that can throw exceptions
        } catch (EntityExistsException e) {
            //  some code
            throw new EntityAlreadyExistsException(e);
        } catch(RuntimeException e) {
            //  some code
            throw new GenericRepositoryException("An unexpected exception occurred while manipulating the database", e);
        }
    }

    //  some other code

}


// exception package
public final class EntityAlreadyExistsException extends GenericRepositoryException{

    public static final String GENERICMESSAGE = "The entity already exists on the table";

    public EntityAlreadyExistsException(Throwable cause){
        super(GENERICMESSAGE, cause);
    }

    //  other constructors

}
于 2012-11-22T11:04:59.693 回答
1

我喜欢 Joshua Bloch 的 Effective Java 2nd edition - Throw exceptions applicable to the abstraction (Item 61) 中的建议。

也就是说,当面对一系列您希望从您的方法中“渗透”出来的异常时,请考虑是否应该用对您的方法更具语义意义的东西重新包装这些异常。

这种方法通常具有将几个较低级别的异常组合成一个较高级别的异常的令人愉悦的副作用。

于 2012-11-22T10:26:29.653 回答