Java样式:正确处理异常
问题内容:
我一直在概念上为我的项目决定异常处理结构。
假设您有一个示例:
public abstract class Data {
public abstract String read();
}
还有两个子类FileData和StaticData,它们从某些指定的文件中读取数据,StaticData仅返回一些预定义的常量数据。
现在,在读取文件时,可能会在FileData中引发IOException,但是StaticData将永远不会抛出。大多数样式指南建议在调用堆栈上传播Exception,直到有足够的上下文可以有效处理它为止。
但是我真的不想在抽象的read()方法中添加throws子句。为什么?因为数据和使用它的复杂机器对文件一无所知,所以它对数据一无所知。此外,可能还有其他Data子类(以及更多子类)永远不会抛出异常并完美地传递数据。
另一方面,IOException是必需的,因为如果磁盘不可读(或某些此类),则 必须
引发错误。因此,我看到的唯一出路是捕获IOException并在其位置抛出一些RuntimeException。
这是正确的哲学吗?
问题答案:
你是对的。
异常应该与所使用的抽象级别相同。这就是自Java 1.4
Throwable开始支持异常链接的原因。例如,对于使用数据库的服务或与“存储”无关的服务,都没有必要抛出FileNotFoundException。
可能是这样的:
public abstract class Data {
public abstract String read() throws DataUnavailableException;
}
class DataFile extends Data {
public String read() throws DataUnavailableException {
if( !this.file.exits() ) {
throw new DataUnavailableException( "Cannot read from ", file );
}
try {
....
} catch( IOException ioe ) {
throw new DataUnavailableException( ioe );
} finally {
...
}
}
class DataMemory extends Data {
public String read() {
// Everything is performed in memory. No exception expected.
}
}
class DataWebService extends Data {
public string read() throws DataUnavailableException {
// connect to some internet service
try {
...
} catch( UnknownHostException uhe ) {
throw new DataUnavailableException( uhe );
}
}
}
请记住,如果您在编程时考虑到继承,则应针对特定方案进行仔细设计,并使用这些方案测试实现。显然,编写通用库比较困难,因为您不知道如何使用它。但是,大多数情况下,应用程序都局限于特定的领域。
您的新异常是运行时还是已检查?这取决于一般规则是抛出运行时错误并检查可恢复条件。
如果可以通过正确编程避免异常(例如NullPointerException或IndexOutOfBounds),请使用运行时
如果异常是由于程序员无法控制的某些外部资源(例如,网络已关闭)引起的,并且可以执行某些操作(在5分钟内显示重试消息等),则应使用已检查的异常。
如果该异常不受程序员的控制,但是可以执行NOTHING,则可以使用RuntimeException。例如,您应该写入文件,但是该文件已被删除,并且您无法重新创建或重试该文件,则该程序很可能在运行时失败(您无能为力)。
请参见有效Java中的以下两项:
- 将检查的异常用于可恢复的条件,将运行时异常用于编程错误
- 抛出适合抽象的异常
我希望这有帮助。