当前位置: 首页 > 知识库问答 >
问题:

什么时候捕捉异常,什么时候抛出异常?

龙骏
2023-03-14

我已经用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中捕获它,然后将其记录为错误。

但我不确定这是否是正确的方法?或者我应该开始在所有方法中捕获异常。这就是为什么这种混乱始于我的 - 我什么时候应该抓住异常与何时应该抛出异常。我知道这是一个愚蠢的问题,但不知何故,我正在努力理解这个主要概念。

有人可以给我一个详细的例子,什么时候捕获异常与何时抛出异常,以便我的概念得到清除吗?在我的情况下,我是否应该继续抛出异常,然后在主调用方法A中捕获它?

共有3个答案

卫彭亮
2023-03-14

总的来说,在你能做一些有用的事情的水平上抓住它。例如,用户试图连接到某个数据库,但在方法d中失败。

你想怎么处理?也许是通过显示一个对话框说“对不起,无法连接到服务器/数据库”或其他什么。是方法A、B还是C创建了这个服务器/数据库信息(比如,通过读取设置文件或要求用户输入)并尝试连接?这可能是处理异常的方法。或者离应该处理它的方法至少1。

它根据您的应用程序而有所不同,因此这只能是非常一般的建议。我的大部分经验都是使用Swing/desktop应用程序,你通常可以根据哪些类在做程序逻辑(例如“控制器”的东西)和谁在弹出对话框(例如“查看”的东西)。通常,“控制器”应该捕获异常并尝试执行某些操作。

在web应用程序中,这可能会有所不同。

一些非常骨架的代码,大多数类都不存在,我不确定数据库的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
  }

}
谷博艺
2023-03-14

在两种情况下,您应该捕获异常。

这是与第三方代码集成的层次,比如ORM工具或任何执行IO操作的库(通过HTTP访问资源、读取文件、保存到数据库,等等)。也就是说,您让应用程序的本机代码与其他组件进行交互的级别。

在此级别,可能会发生您无法控制的意外问题,例如连接失败和文件锁定。

您可能希望通过捕获< code>TimeoutException来处理数据库连接失败,以便在几秒钟后重试。访问文件时的异常也是如此,文件可能在此刻被某个进程锁定,但在下一个瞬间就可用了。

此方案中的指导方针是:

    < li >仅处理特定异常,如< code>SqlTimeoutException或< code>IOException。永远不要处理一般异常(类型为< code>Exception) < li >仅当您对它有意义时才处理它,如重试、触发补偿操作或向异常添加更多数据(如上下文变量),然后重新抛出它 < li >不在此处执行日志记录 < li >让所有其他异常冒泡,因为它们将由第二个案例处理

这将是在将异常直接抛出给用户之前,您可以处理异常的最后一个地方。

您在这里的目标是记录错误并将详细信息转发给程序员,以便他们能够识别并更正错误。添加尽可能多的信息,记录下来,然后向用户显示道歉消息,因为他们可能对此无能为力,特别是如果这是软件中的错误。

第二种情况下的指导方针是:

  • 处理泛型异常类
  • 从当前执行上下文中添加更多信息
  • 记录错误并通知程序员
  • 向用户道歉
  • 尽快
  • 解决

首先,异常代表不可逆转的错误。它们代表系统中的错误、程序员犯的错误或应用程序无法控制的情况。

在这些情况下,用户通常无能为力。因此,您唯一能做的就是记录错误,采取必要的补偿措施,并向用户道歉。如果这是程序员犯的错误,最好让他们知道并修复它,努力实现更稳定的版本。

其次,尝试 catch 块可以屏蔽应用程序执行流,具体取决于它们的使用方式。try catch 块具有与标签及其 goto 伴随项类似的功能,这会导致应用程序执行流从一个点跳转到另一个点。

在开发库的上下文中更容易解释。当您遇到错误时,您应该抛出,除了让API的使用者知道它并让他们决定之外,您别无选择。

假设您是某个数据访问库的开发人员。当你遇到网络错误时,除了抛出一个异常之外,你什么也做不了。从数据访问库的角度来看,这是一个不可逆的错误。

当您开发网站时,这是不同的。您可能会捕获此类异常以进行重试,但如果您希望在从外层收到无效参数时引发异常,因为它们应该已在那里进行验证。

这在表示层中也是不同的,您希望用户提供无效参数。在这种情况下,您只显示一条友好的消息,而不是抛出异常。

如https://roaddd.com/the-only-two-cases-when-you-should-handle-exceptions/

毋树
2023-03-14

当您在知道要做什么的方法中时,您应该捕获异常。

例如,暂时忘记它实际上是如何工作的,假设您正在编写一个用于打开和读取文件的库。

所以你有一个类,说:

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);
        }
    }
}

在这里,程序员知道该做什么,所以他们捕获异常并处理它。

 类似资料:
  • 问题内容: 最近,我接受了公司的采访,他们给了我一个编码问题。我得到了与纸牌有关的程序,其中一种方法是将纸牌洗牌。因此,我将该程序编写为: 在上面的代码中,我引发了我最怀疑的 IllegalArgumentException 。在什么情况下实际上应该抛出运行时异常?我们是否应该实际抛出运行时异常? 谢谢 问题答案: 我们是否应该实际抛出运行时异常? 是的,我们应该。运行时异常有特定的用途-它们发出

  • 问题内容: 在我的应用程序中,有时会引发以下异常: 很难找到错误,因为在stacktrace中没有列出我的方法。那么,有人知道何时抛出此异常吗?感谢您的任何提示。 问题答案: 您可以在stacktrace中看到错误: 适配器的内容已更改,但ListView没有收到通知。确保不从后台线程修改适配器的内容,而仅从UI线程修改。 您应该调查一个线程,并使其与UI线程同步。 在Android中执行此操作的

  • 我们应该在什么时候选择抛出一个异常? 我们可以在try catch中捕获此异常。 在哪种情况下,我们选择使用投掷而不是立即接球?是否与设计模式相关?

  • 我有密码 我想知道抛出怎么会发生这种情况。这显然发生在我的应用程序的一个用户身上,但我无法跟踪出了什么问题。

  • 问题内容: 我担心这是运行时异常,因此应谨慎使用。 标准用例: 但这似乎会强制执行以下设计: 使它回到被检查的异常。 好的,但是让我们开始吧。如果输入错误,则会出现运行时错误。首先,这实际上是统一实施的相当困难的策略,因为您可能必须执行相反的转换: 更糟的是-虽然可以预期客户端代码将以静态方式进行检查,但对于更高级的数据(例如电子邮件地址)却并非如此,或更糟糕的是,必须对数据库进行检查,因此,一般

  • 我担心这是一个运行时异常,所以应该谨慎使用。 标准用例: 但这似乎会迫使以下设计: 将其恢复为检查异常。 好吧,但我们还是继续吧。如果输入错误,则会出现运行时错误。因此,首先,这实际上是一个很难统一实施的政策,因为您可能需要进行相反的转换: 更糟糕的是,在检查