Java 何时捕获异常与何时抛出异常?
我用Java编写代码已经有一段时间了。但是有时候,我不明白什么时候应该抛出异常,什么时候应该捕获异常。我正在做一个有很多方法的项目。层次结构是这样的-Java 何时捕获异常与何时抛出异常?,java,exception,throw,Java,Exception,Throw,我用Java编写代码已经有一段时间了。但是有时候,我不明白什么时候应该抛出异常,什么时候应该捕获异常。我正在做一个有很多方法的项目。层次结构是这样的- Method A will call Method B and Method B will call some Method C and Method C will call Method D and Method E. 所以目前我正在做的是——我在所有方法中抛出异常,并在方法A中捕获它,然后作为错误记录 但我不确定这样做是否正确?或者我应该开
Method A will call Method B and Method B will call some Method C and Method C will call Method D and Method E.
所以目前我正在做的是——我在所有方法中抛出异常,并在方法A中捕获它,然后作为错误记录
但我不确定这样做是否正确?或者我应该开始捕获所有方法中的异常。因此,这就是为什么这种困惑始于我的-我应该在什么时候捕获异常,还是应该在什么时候抛出异常。我知道这是一个愚蠢的问题,但不知何故,我正在努力理解这个主要概念
有没有人能给我一个详细的例子,说明什么时候捕获异常,什么时候抛出异常,这样我的概念就清楚了?在我的例子中,我是否应该继续抛出异常,然后在主调用方法A中捕获它?通常,在您可以对它做一些有用的事情的级别上捕获它。例如,用户试图连接到某个数据库,但在方法D中失败 你想怎么处理?可能通过弹出一个对话框说“对不起,无法连接到服务器/DB”或其他什么。方法A、B或C是否创建了此服务器/DB信息(例如,通过读取设置文件或请求用户输入)并尝试了连接?这可能就是应该处理异常的方法。或者至少与应该处理它的方法相差1 它确实因应用程序而异,因此这只能是非常一般的建议。我的大部分经验都是使用Swing/桌面应用程序,你通常可以根据哪些类在执行程序逻辑(例如“控制器”之类的东西)以及谁在设置对话框(例如“查看”之类的东西)来感受。通常,“控制器”应该捕获异常并尝试执行某些操作 在web应用程序中,这可能会有所不同 一些非常简单的代码,大多数类都不存在,我也不确定DB的URL是否有意义,但你明白了。模糊的摇摆
/* gets called by an actionListener when user clicks a menu etc... */
public URL openTheDB() {
URL urlForTheDB = MyCoolDialogUtils.getMeAURL(URL somePreviousOneToFillInTheStart);
try {
verifyDBExists(urlForTheDB);
// this may call a bunch of deep nested calls that all can throw exceptions
// let them trickle up to here
// if it succeeded, return the URL
return urlForTheDB;
}
catch (NoDBExeption ndbe) {
String message = "Sorry, the DB does not exist at " + URL;
boolean tryAgain = MyCoolDialogUtils.error(message);
if (tryAgain)
return openTheDB();
else
return null; // user said cancel...
}
catch (IOException joe) {
// maybe the network is down, aliens have landed
// create a reasonable message and show a dialog
}
}
当您使用知道该做什么的方法时,应该捕获异常 例如,暂时忘记它实际上是如何工作的,假设您正在编写一个用于打开和读取文件的库 你有一门课,比如说:
public class FileInputStream extends InputStream {
public FileInputStream(String filename) { }
}
现在,假设该文件不存在。你该怎么办?如果你在苦苦思索答案,那是因为没有答案。。。FileInputStream
不知道如何解决该问题。所以它把它抛到链条上,即:
public class FileInputStream extends InputStream {
public FileInputStream(String filename) throws FileNotFoundException { }
}
现在,假设有人在使用你的图书馆。他们可能有如下代码:
public class Main {
public static void main(String... args) {
String filename = "foo.txt";
try {
FileInputStream fs = new FileInputStream(filename);
// The rest of the code
} catch (FileNotFoundException e) {
System.err.println("Unable to find input file: " + filename);
System.err.println("Terminating...");
System.exit(3);
}
}
}
在这里,程序员知道该做什么,所以他们捕获异常并处理它。当您想要通知调用方某些失败的方法时,通常会抛出异常
e、 g无效的用户输入、数据库问题、网络中断、缺少文件您应该以尽可能低的级别处理异常。如果方法不能正确处理异常,则应该抛出它
- 如果您有连接到资源的方法(例如打开文件/网络),则捕获
- 如果层次结构中较高的类需要有关错误的信息,则抛出
例如,如果您正在编写代码,从保存文件中读取有关连接播放机的信息,并且您的一个I/O方法抛出了一个
IOException
,那么您可能希望抛出该异常,而调用load
方法的代码可能希望捕获该异常并相应地处理它(如断开播放器连接,或向客户端发送响应等)。您不想在load
方法中处理异常的原因是,在该方法中,您无法有意义地处理异常,因此您将异常委托给调用者,希望调用者能够处理它。我将共享一个在一两个生产环境中保存了bacon的模式
动机
我的目标是确保在午夜试图解决sev1支持问题的可怜的家伙(可能是我)得到一个很好的由错误引起的层次结构,包括ID之类的数据,而不会使代码过于混乱
方法
为了实现这一点,我捕获所有已检查的异常,并将它们作为未检查的异常重新抛出。然后,我在每个体系结构层的边界处使用一个全局捕获(通常是抽象的或注入的,因此只编写一次)在这些点上,我可以向错误堆栈添加额外的上下文,或者决定是否记录和忽略,或者引发带有变量的自定义检查异常以保存任何额外的上下文。另一方面,我只在顶层记录错误,以阻止发生“双重记录”(例如cron作业,ajax的spring控制器)
使用这种方法,您的GUI或业务层的方法签名不会因为必须为数据库相关异常声明“抛出”而变得混乱
这在现实生活中如何起作用的示例:
假设我的代码的工作是一个自动更新多份保险单的过程。该体系结构支持GUI手动触发一份保险单的更新。还可以说,其中一份保险单的DB中评级区域的邮政编码已损坏
我希望实现的错误日志类型的一个示例是
日志消息:由于错误,正在标记策略1234以进行手动干预:
从堆栈跟踪:错误续订策略1234。正在回滚事务…此捕获还将覆盖诸如保存错误或生成信函等错误
从圣
throw new RuntimeException(checked,"Could not retrieve contact " + id);