何时捕获异常(高级别与低级别)?
When to catch the exceptions (high level vs. low level)?
我创建了以下 classes:
- 抽象记录器class
- 实现实际记录器
的抽象记录器class的三个子classes
- Class 作为记录器的接口
三个子class可以抛出异常(创建文件、写入文件等)。
是直接在三个subclass中捕获异常,还是重新抛到那里,在接口中捕获?或者可能捕获使用记录器接口的 class?
其次,我有一个 class 可以解析设置文件。我用单例模式实现了它(运行时只有一个实例)。当然,在此 class 中可能会出现异常(NullPointerException 和 IOException)。
我应该直接在这个 class 中捕获这些异常,还是将其重新抛给那个 class 的客户端?
我的普遍问题是我不知道什么时候必须捕获异常以及什么时候重新抛出它。
在我看来,异常应该总是传播回调用者。您始终可以捕获、记录然后从 class 本身重新抛出相同的或自定义的异常,但最终它应该由调用者处理。
例如,
如果 DataAccessException
出现在你的 DAO Class 中,那么你可以在你的 DAO 中捕获并记录它,然后重新抛出一个自定义异常,该异常被传播到调用者 Class 然后调用者应该决定它需要如何处理该异常。
部分 Liskov substitution principle 状态:
No new exceptions should be thrown by methods of the subtype, except where those exceptions are themselves subtypes of exceptions thrown by the methods of the supertype.
当在客户端代码中用一种类型替换另一种类型时,任何异常处理代码都应该仍然有效。
如果您选择使用 checked exceptions,Java 会强制执行此操作。 (这不是建议使用检查异常,但我会在这里使用来演示原理)。
这并不是说您应该捕获所有异常并进行转换。异常可能是意外的(即 RuntimeExceptions
在已检查的异常环境中),您应该只翻译匹配的异常。
示例:
public class NotFoundException {
}
public interface Loader {
string load() throws NotFoundException;
}
用法:
public void clientCode(Loader loader) {
try{
string s = loader.load();
catch (NotFoundException ex){
// handle it
}
}
这是一个很好的实现,它捕获了捕获和翻译有意义的异常,并传播了其余部分。
public class FileLoader implements Loader {
public string load() throws NotFoundException {
try{
return readAll(file);
} catch (FileNotFoundException ex) {
throw new NotFoundException(); // OK to translate this specific exception
} catch (IOException ex) {
// catch other exception types we need to and that our interface does not
// support and wrap in runtime exception
throw new RuntimeException(ex);
}
}
}
这是翻译所有异常的错误代码,不需要满足 Liskov:
public class FileLoader implements Loader {
public string load() throws NotFoundException {
try{
return readAll(file);
} catch (Exception ex) {
throw new NotFoundException(); //assuming it's file not found is not good
}
}
}
当您知道如何处理该异常时,您应该捕获该异常。
My general problem is that I don't know when I have to catch the exceptions and when to rethrow it.
这表明您应该 throws
方法上的异常,因为您不知道在那个阶段如何处理异常。
我创建了以下 classes:
- 抽象记录器class
- 实现实际记录器 的抽象记录器class的三个子classes
- Class 作为记录器的接口
三个子class可以抛出异常(创建文件、写入文件等)。
是直接在三个subclass中捕获异常,还是重新抛到那里,在接口中捕获?或者可能捕获使用记录器接口的 class?
其次,我有一个 class 可以解析设置文件。我用单例模式实现了它(运行时只有一个实例)。当然,在此 class 中可能会出现异常(NullPointerException 和 IOException)。
我应该直接在这个 class 中捕获这些异常,还是将其重新抛给那个 class 的客户端?
我的普遍问题是我不知道什么时候必须捕获异常以及什么时候重新抛出它。
在我看来,异常应该总是传播回调用者。您始终可以捕获、记录然后从 class 本身重新抛出相同的或自定义的异常,但最终它应该由调用者处理。
例如,
如果 DataAccessException
出现在你的 DAO Class 中,那么你可以在你的 DAO 中捕获并记录它,然后重新抛出一个自定义异常,该异常被传播到调用者 Class 然后调用者应该决定它需要如何处理该异常。
部分 Liskov substitution principle 状态:
No new exceptions should be thrown by methods of the subtype, except where those exceptions are themselves subtypes of exceptions thrown by the methods of the supertype.
当在客户端代码中用一种类型替换另一种类型时,任何异常处理代码都应该仍然有效。
如果您选择使用 checked exceptions,Java 会强制执行此操作。 (这不是建议使用检查异常,但我会在这里使用来演示原理)。
这并不是说您应该捕获所有异常并进行转换。异常可能是意外的(即 RuntimeExceptions
在已检查的异常环境中),您应该只翻译匹配的异常。
示例:
public class NotFoundException {
}
public interface Loader {
string load() throws NotFoundException;
}
用法:
public void clientCode(Loader loader) {
try{
string s = loader.load();
catch (NotFoundException ex){
// handle it
}
}
这是一个很好的实现,它捕获了捕获和翻译有意义的异常,并传播了其余部分。
public class FileLoader implements Loader {
public string load() throws NotFoundException {
try{
return readAll(file);
} catch (FileNotFoundException ex) {
throw new NotFoundException(); // OK to translate this specific exception
} catch (IOException ex) {
// catch other exception types we need to and that our interface does not
// support and wrap in runtime exception
throw new RuntimeException(ex);
}
}
}
这是翻译所有异常的错误代码,不需要满足 Liskov:
public class FileLoader implements Loader {
public string load() throws NotFoundException {
try{
return readAll(file);
} catch (Exception ex) {
throw new NotFoundException(); //assuming it's file not found is not good
}
}
}
当您知道如何处理该异常时,您应该捕获该异常。
My general problem is that I don't know when I have to catch the exceptions and when to rethrow it.
这表明您应该 throws
方法上的异常,因为您不知道在那个阶段如何处理异常。