我在C#入门书中读到,如果你不知道如何处理它,你不应该发现异常。在使用Java编程时考虑到这些建议,我有时会发现我不知道如何处理异常,但我不得不抓住它或“渗透它”以避免编译错误。我宁愿不要在调用树的整个过程中使用throws
子句来混淆方法,所以我经常使用“转换”异常到RuntimeException
,如下所示。将throws
子句添加到许多方法中以用于未真正“处理”(正确处理)的异常似乎冗长且分散注意力。是以下不好的风格,如果有的话,有什么更好的方法来解决这个问题?
try {
thread.join();
}
catch (InterruptedException e) {
Console.printwriter.format("%s\n", e.printStackTrace());
throw new RuntimeException();
}
编辑:除了杂乱之外,渗透异常还有另一个问题:在代码修订之后,你可能最终会得到一些不必要的throws
子句。我知道清除它们的唯一方法是通过反复试验:删除它们并查看编译器是否抱怨。显然,如果您想保持代码清洁,这很烦人。
答案 0 :(得分:5)
已检查和未检查的例外之间的Java划分为somewhat controversial。
如果您控制接口,那么在签名中添加throws子句通常是最好的方法。
如果您处于无法处理异常的情况,但由于检查了异常签名而不允许它冒泡,那么将异常包装到可以重新抛出的异常中(通常是RuntimeException)常见的做法。
在许多情况下,您希望使用另一个已检查的异常,例如IOException或SQLException。但这并不总是一种选择。
但在您的示例中,将原始异常包含为“原因”:
throw new RuntimeException(e);
这也可以消除对日志记录的需要(因为这也可以推迟到可以处理异常的人,并且所有信息仍然存在)。
答案 1 :(得分:1)
如果您不知道如何处理异常,则不应该抓住它。因此,您的方法现在将抛出异常,因此如果它不是运行时异常,它应该有一个throws子句。他们没有错。
答案 2 :(得分:1)
我喜欢Joshua Bloch的Effective Java 2nd edition中的建议 - 抛出适合抽象的例外(第61项)。
也就是说,当你面对一系列例外时,你希望从你的方法中“渗透”出来,考虑是否应该用对你的方法更具语义意义的东西重新包装异常。
这种方法通常会产生令人愉悦的副作用,即将几个较低级别的异常组合成单个较高级别的异常。
答案 3 :(得分:1)
良好的编程实践告诉您应该隐藏对象的内部状态,至少对我来说,还包括异常。您应该看到该异常的含义是什么,并向您的类的调用者返回表示该含义的异常。
如果框架已经提供了具有该含义的异常,例如IllegalArgumentException,则应该实例化一个新对象,给它一个字符串,其中包含对所发生事件的良好描述并封装所引发的异常,这与新的IllegalArgumentException类似( "由于......",e),参数X无效; 如果框架没有针对您的问题的良好描述性异常,您应该创建自己的一组例外。我通常为该项目/包创建一个通用异常(它将扩展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
}