我不明白在代码中使用链式异常的优点。
考虑到ResourceLoader example from java world,如果程序员知道遇到ResourceLoadException
的可能性,为什么不捕获相同的异常而不是SQLException
?另外,程序员可以捕获相同代码中的异常而不是必须抛出新的Throwable
实例?
答案 0 :(得分:15)
有人可以提供有关链式例外需求的信息吗?
文章说得很好:
异常链接允许您将一种异常类型映射到另一种异常类型,以便方法可以抛出在与方法本身相同的抽象级别定义的异常,而不会丢弃重要的调试信息。
也就是说,如果你有一个从数据库加载某个对象的方法,你可能更想要一些ResourceLoadException
(与方法抽象级别更接近)而不是低级别SQLException
如果这是问题的原始来源。但是,如果您只是抓住SQLException
并抛出ResourceLoadException
,则可能会丢失重要的调试信息。
因此,链接例外是一个很好的选择。你抛出一个“高级”异常,非常适合特定方法,但是将其链接到导致它的异常。
否则,程序员可以捕获相同代码中的异常,而不是抛出一个新的Throwable实例?
我不太理解你的推理。关键是他不应该担心这个抽象层次的SQLException
。
答案 1 :(得分:15)
为什么链异常?
我们需要链接异常以使日志可读。
以下列示例1.没有链接和2.链接,例外以感受差异
创建以下例外
class NoLeaveGrantedException extends Exception {
public NoLeaveGrantedException(String message, Throwable cause) {
super(message, cause);
}
public NoLeaveGrantedException(String message) {
super(message);
}
}
class TeamLeadUpsetException extends Exception {
public TeamLeadUpsetException(String message, Throwable cause) {
super(message, cause);
}
public TeamLeadUpsetException(String message) {
super(message);
}
}
class ManagerUpsetException extends Exception {
public ManagerUpsetException(String message, Throwable cause) {
super(message, cause);
}
public ManagerUpsetException(String message) {
super(message);
}
}
class GirlFriendOfManagerUpsetException extends Exception {
public GirlFriendOfManagerUpsetException(String message, Throwable cause) {
super(message, cause);
}
public GirlFriendOfManagerUpsetException(String message) {
super(message);
}
}
现在使用
<强> 1。没有链接
public class MainClass {
public static void main(String[] args) throws Exception {
getLeave();
}
static void getLeave() throws NoLeaveGrantedException {
try {
howIsTeamLead();
} catch (TeamLeadUpsetException e) {
e.printStackTrace();
throw new NoLeaveGrantedException("Leave not sanctioned.");
}
}
static void howIsTeamLead() throws TeamLeadUpsetException {
try {
howIsManager();
} catch (ManagerUpsetException e) {
e.printStackTrace();
throw new TeamLeadUpsetException(
"Team lead is not in good mood");
}
}
static void howIsManager() throws ManagerUpsetException {
try {
howIsGirlFriendOfManager();
} catch (GirlFriendOfManagerUpsetException e) {
e.printStackTrace();
throw new ManagerUpsetException("Manager is in bad mood");
}
}
static void howIsGirlFriendOfManager()
throws GirlFriendOfManagerUpsetException {
throw new GirlFriendOfManagerUpsetException(
"Girl friend of manager is in bad mood");
}
}
<强> 2。链强>
public class MainClass {
public static void main(String[] args) throws Exception {
getLeave();
}
static void getLeave() throws NoLeaveGrantedException {
try {
howIsTeamLead();
} catch (TeamLeadUpsetException e) {
throw new NoLeaveGrantedException("Leave not sanctioned.", e);
}
}
static void howIsTeamLead() throws TeamLeadUpsetException {
try {
howIsManager();
} catch (ManagerUpsetException e) {
throw new TeamLeadUpsetException(
"Team lead is not in good mood", e);
}
}
static void howIsManager() throws ManagerUpsetException {
try {
howIsGirlFriendOfManager();
} catch (GirlFriendOfManagerUpsetException e) {
throw new ManagerUpsetException("Manager is in bad mood", e);
}
}
static void howIsGirlFriendOfManager()
throws GirlFriendOfManagerUpsetException {
throw new GirlFriendOfManagerUpsetException(
"Girl friend of manager is in bad mood");
}
}
现在比较日志
<强> 1。没有链接
com.bskyb.svod.autoingest.GirlFriendOfManagerUpsetException: Girl friend of manager is in bad mood
at com.bskyb.svod.autoingest.MainClass.howIsGirlFriendOfManager(MainClass.java:61)
at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:52)
at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:43)
at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34)
at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)
com.bskyb.svod.autoingest.ManagerUpsetException: Manager is in bad mood
at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:55)
at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:43)
at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34)
at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)
com.bskyb.svod.autoingest.TeamLeadUpsetException: Team lead is not in good mood
at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:46)
at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34)
at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)
Exception in thread "main" com.bskyb.svod.autoingest.NoLeaveGrantedException: Leave not sanctioned.
at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:37)
at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)
<强> 2。链强>
Exception in thread "main" com.bskyb.svod.autoingest.NoLeaveGrantedException: Leave not sanctioned.
at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:36)
at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29)
Caused by: com.bskyb.svod.autoingest.TeamLeadUpsetException: Team lead is not in good mood
at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:44)
at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34)
... 1 more
Caused by: com.bskyb.svod.autoingest.ManagerUpsetException: Manager is in bad mood
at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:52)
at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:42)
... 2 more
Caused by: com.bskyb.svod.autoingest.GirlFriendOfManagerUpsetException: Girl friend of manager is in bad mood
at com.bskyb.svod.autoingest.MainClass.howIsGirlFriendOfManager(MainClass.java:58)
at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:50)
... 3 more
答案 2 :(得分:5)
优点是调用者只需处理ResourceLoadException
而不是SQLException
。这样,如果您以后将数据存储更改为访问它的文件可能会导致IOException
。您不必返回并更改调用者处理的Exception类型。这对调用者很有用,因为调用者将以相同的方式处理任一异常。
答案 3 :(得分:5)
loadResource
的调用者不需要知道这些资源的加载方式的确切细节,或者至少不关心失败原因的详细信息。 (请记住,编写loadResources
可能不是您,或者可能是需要使用loadResources方法的其他人。)
调用loadResource时你应该关心的是它可能抛出ResourceLoadException。并非由于SQLException而导致实现细节失败 - 这可能会随着时间的推移而改变,稍后某人可能会决定从其他可能失败的地方加载资源。
您只需要加载一些资源,如果失败则需要处理,并且不处理潜在的MainframeHasCrashedException,FileNotFoundException以及加载这些资源的其他十几个原因可能会失败。
现在,当某些内容失败时,使用导致失败的原始异常(例如SQLException)非常方便 - 因此搜索日志文件或类似内容的人可以通过检查stacktrace找出错误的原因
如果loadResources也可以抛出其他异常,那么你不应该只想在这里捕获Exception。一个UnautorizedException,你可能不想在调用loadResources时处理它 - 你可能希望将该异常传播给其他可以处理UnautorizedException的调用者(并且可能会提示用户输入一些凭据)。一个catch(Exception e)会吞下UnautorizedException,你实在无法处理它。
答案 4 :(得分:2)
第一个好处是封装。 ResourceLoader可能是具有多个实现的接口(例如,一个从数据库加载资源,而另一个从文件系统加载它们),其中在运行时选择要使用的实现。然后调用者应该知道为什么加载资源失败的根本原因,但可能仍然希望对资源加载失败做出反应。如果接口声明要抛出的两个不同异常(调用者可能希望以不同方式响应)(例如,可能导致重试的TransientResourceLoadFailureException,以及已知重试未成功的PermanentResourceLoadFailureException),这将特别有用。
异常链接的第二个好处是链中的每个异常都可能有不同的消息,这允许包含用于调试的附加信息。在您的情况下,请注意ResourceLoadException的消息包含无法加载的资源的名称,这不能保证包含在SQLException中,但可能需要重现该问题(某些数据库并不完全为特定错误所知)消息)。
这些好处是以必须编写和维护catch块为代价的。您应该根据具体情况决定收益是否合理。
答案 5 :(得分:1)
我认为该样本的原因是作者希望创建一个统一的接口,它不依赖于某些特定的底层系统,比如SQL。因此,他将异常转换为更通用的形式,使实际的实现对业务逻辑透明。
但是,在某些情况下,可能需要传播类似SQLException的错误。这对于需要根据抛出的异常采取不同操作的地方非常有用。
答案 6 :(得分:0)
链式异常是出于调试目的。当您获得一般性异常时,可以检查是否存在链式下层异常,并尝试了解为什么发生该下层异常。