我不明白在代码中出现链式异常的优点。链式异常的优势是什么
考虑到ResourceLoader example from java world,如果程序员知道遇到ResourceLoadException
的可能性,为什么不捕获相同的异常而不是SQLException
?否则,程序员可以在同一代码中捕获两个例外情况,而不必抛出一个新的Throwable
实例?
我不明白在代码中出现链式异常的优点。链式异常的优势是什么
考虑到ResourceLoader example from java world,如果程序员知道遇到ResourceLoadException
的可能性,为什么不捕获相同的异常而不是SQLException
?否则,程序员可以在同一代码中捕获两个例外情况,而不必抛出一个新的Throwable
实例?
任何人都可以提供需要链式异常的信息吗?
文章说,这非常好:
异常链可以让你一个异常类型映射到另一个,这样的方法可以抛出在同一抽象级别的方法本身定义的异常而不会丢弃重要的调试信息。
也就是说,如果你有一个从数据库加载某些对象的方法,你可能反而需要一些ResourceLoadException
(上的相关方法抽象级别),而不是一个低级别的SQLException
即使是问题的原始来源。但是,如果您只是简单地捕获SQLException
并抛出ResourceLoadException
,则可能会丢失重要的调试信息。
因此,链接例外是一个很好的选择。您会抛出一个“高级”异常,非常适合特定的方法,但将其与导致异常的异常链接起来。
否则,程序员可以在相同的代码中捕获两个异常,而不是抛出一个新的Throwable实例吗?
我不太关注你的推理。关键是他不应该在这个抽象层次上担心SQLException
。
我认为这个例子的原因是作者希望创建一个不依赖于某些特定底层系统(如SQL)的统一接口。因此,他将异常转换为更一般的形式,使实际实现对业务逻辑透明。
但是,在某些情况下,可能需要传播像SQLException这样的错误。这在基于抛出的异常需要采取不同操作的地方很有用。
优点是主叫方只需处理ResourceLoadException
而不是SQLException
。这样,如果稍后将数据存储更改为访问该文件的文件可能会导致IOException
。您不必返回并更改调用方处理的异常类型。这对你的调用者很有用,因为调用者要以相同的方式处理异常。
loadResource
的调用者不需要知道如何加载这些资源的确切细节,或者至少不关心其失败原因的细节。 (请记住它可能不是你写的loadResources
,或者它可能是其他人需要使用loadResources方法)。
当你调用loadResource时,你应该关心的是它可能抛出ResourceLoadException异常。并非由于SQLException而导致实现细节失败 - 这也可能随着时间而改变,稍后有人可能会决定从其他地方加载可能会失败的资源。
你只需要加载一些资源,如果它失败,你需要处理,并且不处理潜在的MainframeHasCrashedException,FileNotFoundException和加载这些资源的其他十几个原因可能会失败。
现在,如果有些地方工作不及格,这是方便有导致失败,如一个SQLException原始异常 - 所以有人通过日志文件或淘类似可以通过检查堆栈跟踪
找出错误的原因如果loadResources也可能抛出其他异常,例如在这里你不应该试图捕获Exception。一个UnautorizedException,当你调用loadResources时你可能不想处理这个问题 - 你可能想把这个异常传播给可以处理UnautorizedException的其他调用者(也许提示用户输入一些凭证)。一个catch(Exception e)会吞下那个你真的无法在那里处理的UnautorizedException。
第一个好处是封装。 ResourceLoader可能是一个与多个实现的接口(例如一个从数据库加载资源,另一个从文件系统加载它们),在运行时选择要使用的实现。那么调用者应该不知道为什么加载资源失败的根本原因,但可能仍希望对资源加载失败做出反应。如果接口声明调用者可能希望以不同方式响应的两个不同异常(例如,TransientResourceLoadFailureException(重试可能取消的地方)以及PermanentResourceLoadFailureException(重试地址已知不成功)),则此方法特别有用。
异常链接的第二个好处是链中的每个异常都可能有不同的消息,这允许包含用于调试的附加信息。在你的情况下,请注意ResourceLoadException的消息包含无法加载的资源的名称,不保证包含在SQLException中,但可能需要重现该问题(某些数据库并不完全知道特定的错误消息)。
这些好处是以编写和维护catch块为代价的。您应该根据具体情况决定是否可以获得成本。
为什么连锁异常?
我们需要链接异常以使日志可读。
取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
好。我的观点是:以下更改会出现什么问题(仅显示必要的更改)? `try {} catch(SQLException e){} catch(ResourceLoadException f){}`。但我理解你有关于更密切相关的异常的观点。但是现在我的问题是,如果自定义异常与实际异常无关,即异常实际上是“SQLException”而不是“ResourceLoadException”,那么异常处理代码可能是错误指导? – 2011-02-16 19:18:39
该代码更改没有任何错误,但正如我所说的,根本没有必要在该抽象级别捕获“SQLException”。例如,如果有两个资源加载类:`MysqlResourceLoader`和`FileResourceLoader`,它们共享一个通用接口`ResourceLoader`。那么`loadResource`方法显然不应该被声明为抛出`SQLException`。 (如果我给你一个`ResourceLoader`并且你不知道它是实际类型呢?) – aioobe 2011-02-16 19:31:19
问题是你可能有一个接口在抽象层面抛出一个特定的异常类型。在实现该接口时可能需要捕获SQLException或其他。接口的全部要点就是坚持下去,不需要改变它,无论实现的内容是什么......如果这是有道理的。另外,在这种情况下,父类将不知道如何处理SQLException。它需要做的唯一事情就是总结“我们被搞砸了”,打印出一个错误,让用户修复它。 – user606723 2011-02-16 19:43:07