我创建了以下类:
这三个子类可以抛出异常(创建文件,写入文件等)。
我应该直接在三个子类中捕获异常,还是在那里重新抛出异常并在接口中捕获它?或者可能在使用记录器接口的类中捕获?
其次,我有一个解析设置文件的类。我使用单例模式(在运行时只有一个实例)。当然,在这个类中可能会发生异常(NullPointerException和IOException)。
我应该直接在这个类中捕获这些异常,还是将它重新抛给该类的客户端?
我的一般问题是,我不知道何时必须捕捉异常以及何时重新抛出异常。
答案 0 :(得分:3)
部分Liskov substitution principle州:
子类的方法不应抛出新的异常,除非这些异常本身是超类型方法抛出的异常的子类型。
在客户端代码中将一种类型替换为另一种类型时,任何异常处理代码仍应起作用。
如果您选择使用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
}
}
}
答案 1 :(得分:2)
当您知道如何处理该异常时,您应该捕获异常。
我的一般问题是,我不知道何时必须捕捉异常以及何时重新抛出异常。
这表明你应该throws
方法的异常,因为你不知道在那个阶段如何处理异常。
答案 2 :(得分:1)
在我看来,异常应该总是传播回调用者。您可以随时捕获,记录然后从类本身重新抛出相同或自定义的异常,但最终应该由调用者处理。
例如,
如果您的DAO课程中出现DataAccessException
,那么您可以抓住&在你的DAO中记录这个,然后重新抛出一个传播给调用者类的自定义异常,然后调用者应该决定它需要对该异常做什么。