AKI*_*WEB 39 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中捕获它然后记录为错误.
但我不确定这是否是正确的方法呢?或者我应该开始捕获所有方法中的异常.所以这就是为什么这种混乱开始于我 - 我应该何时捕获异常与何时应该抛出异常.我知道这是一个愚蠢的问题,但不知怎的,我正在努力理解这个主要概念.
有人能给我一个详细的例子,When to catch the Exception vs When to throw the Exceptions以便我的概念得到澄清吗?在我的情况下,我应该继续抛出异常然后在主调用方法A中捕获它吗?
dur*_*597 56
当你在知道该做什么的方法中时,你应该捕获异常.
例如,忘记它实际上是如何工作的,假设你正在编写一个用于打开和读取文件的库.
所以你有一节课,说:
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);
        }
    }
}
在这里,程序员知道该怎么做,所以他们捕获异常并处理它.
Phi*_*ana 15
有两种情况您应该捕获异常。
这是您与第三方代码集成的级别,例如 ORM 工具或任何执行 IO 操作的库(通过 HTTP 访问资源、读取文件、保存到数据库,等等)。也就是说,您让应用程序的本机代码与其他组件交互的级别。
在此级别,可能会出现您无法控制的意外问题,例如连接失败和锁定文件。
您可能希望通过捕获 a 来处理数据库连接失败,TimeoutException 以便您可以在几秒钟后重试。访问文件时的异常也是如此,该文件可能在当前被进程锁定,但在下一瞬间可用。
这种情况下的指导方针是:
SqlTimeoutExceptionor IOException。永远不要处理通用异常(类型Exception)在将异常直接抛出给用户之前,这将是您可以处理异常的最后一个地方。
您在这里的目标是记录错误并将详细信息转发给程序员,以便他们能够识别和纠正错误。添加尽可能多的信息,记录下来,然后向用户显示一条道歉信息,因为他们可能对此无能为力,尤其是如果它是软件中的错误。
第二种情况的指导方针是:
首先,异常代表不可逆转的错误。它们代表系统中的错误、程序员犯的错误或应用程序无法控制的情况。
在这些情况下,用户通常无能为力或无能为力。因此,您唯一能做的就是记录错误,采取必要的补偿措施,并向用户道歉。如果这是程序员犯的错误,最好让他们知道并修复它,朝着更稳定的版本努力。
其次,try catch块可以根据它们的使用方式屏蔽应用程序执行流。阿try catch块具有类似的功能是alabel和它的goto同伴,这会导致应用程序的执行流程从一个点跳到另一个。
在开发库的上下文中更容易解释。您应该在遇到错误时抛出异常,除了让 API 的使用者知道并让他们做出决定之外,您无能为力。
假设您是某个数据访问库的开发人员。当您遇到网络错误时,除了抛出异常之外,您无能为力。从数据访问库的角度来看,这是一个不可逆转的错误。
这在您开发网站时有所不同。您可能会捕获此类异常以重试,但如果您从外层接收到无效参数,则希望抛出异常,因为它们应该在那里得到验证。
这在表示层中又有所不同,您希望用户提供无效参数。在这种情况下,您只需显示一条友好消息而不是抛出异常。
正如https://roaddd.com/the-only-two-cases-when-you-should-handle-exceptions/
当函数遇到故障(即错误)时,应抛出异常.
功能是一个工作单元,故障应视为错误或基于其对功能的影响.在一个函数˚F,失败是错误的,当且仅当它可以防止˚F不能满足其任何被叫者的先决条件,实现任何的˚F自己的后置条件,或者重新建立任何不变的是˚F维持股份责任.
有三种不同的错误:
任何其他条件都不是错误,不应报告为错误.
在函数检测到错误的情况下报告错误,该错误无法处理自身并阻止其以任何形式的正常或预期操作继续.
在有足够知识处理错误,转换错误或强制执行错误策略中定义的边界的位置处理错误,例如在主要或线程主线上.
一般来说,抓住你可以做一些有用的事情的水平。例如,用户尝试连接到某个数据库,但在方法 D 中失败。
你想怎么处理?也许通过放置一个对话框说“对不起,无法连接到服务器/数据库”或其他什么。是方法 A、B 或 C 创建了此 SERVER/DB 信息(例如,通过读取设置文件或要求用户输入)并尝试连接?这可能是应该处理异常的方法。或者距离应该处理它的方法至少 1。
它确实因您的应用程序而异,因此这只能是非常一般的建议。我的大部分经验是使用 Swing/桌面应用程序,您通常可以根据哪些类在执行程序逻辑(例如“控制器”)和谁在放置对话框(例如“视图”)来感受。通常“控制器”应该捕获异常并尝试做一些事情。
在网络应用程序中,这可能有所不同。
一些非常骨架的代码,大多数类都不存在,我不确定数据库的 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
  }
}
您应该在尽可能低的级别上处理异常。如果方法无法正确处理异常,则应该抛出它。
我将分享一种模式,在我或两个生产环境中保存我的培根.
动机
我的目标是确保那个在午夜时分试图解决sev1支持票的穷人(也许是我)得到一个很好的层次结构,由'错误'跟随,完成ID等数据,所有这些都没有过多的混乱代码.
方法
为了实现这一点,我捕获所有已检查的异常并将其作为未经检查的异常重新抛出.然后,我在每个架构层的边界处使用全局捕获(通常是抽象或注入,因此它只被写入一次).在这些点上,我可以向错误堆栈添加额外的上下文,或者决定是否记录和忽略,或者使用变量引发自定义检查的异常来保存任何额外的上下文.另外,我只记录顶层的错误以阻止'双重记录'的发生(例如,cron作业,ajax的弹簧控制器)
throw new RuntimeException(checked,"Could not retrieve contact " + id);
使用这种方法,不必为数据库相关异常声明"throws",从而使GUI或业务层的方法签名不会混乱.
现实生活中如何运作的一个例子:
让我们说我的代码的工作是一个自动化的过程来更新许多保险政策.该体系结构支持GUI以手动触发一个策略的续订.还可以说,对于其中一个策略,数据库中的评级区域的邮政编码已损坏.
我想要实现的错误日志类型的一个例子.
日志消息:由于错误而将标记策略1234标记为手动干预:
从堆栈跟踪:错误更新策略1234.回滚事务... 此捕获还将涵盖诸如保存错误或生成字母之类的错误.
从堆栈跟踪:引起:错误评级策略1234 ... 此捕获将检索错误检索许多其他对象,以及算法错误,如NPE等...
来自堆栈跟踪:引起:错误检索评级区域73932 ...
来自堆栈跟踪:引起:JPA:字段'postcode'中的意外null