投掷或尝试接住
Posted
技术标签:
【中文标题】投掷或尝试接住【英文标题】:Throws or try-catch 【发布时间】:2011-03-13 07:27:03 【问题描述】:在决定是向方法中添加throws
子句还是使用try-catch
时,一般的经验法则是什么?
根据我自己的阅读,throws
应该在调用者违反合同结束(传递的对象)时使用,try-catch
应该在操作期间发生异常时使用在方法内部进行。它是否正确?如果是这样,调用方应该怎么做?
P.S:通过 Google 和 SO 进行搜索,但希望对此有明确的答案。
【问题讨论】:
我一直很喜欢“如果在这里处理它有意义......那就去做”的方法。 我喜欢在发生异常的地方处理所有异常,这样我就不必处理未来的问题了。 【参考方案1】: 仅当您能够以有意义的方式处理异常时才捕获异常 如果要由当前方法的使用者处理,则声明向上抛出异常 如果异常是由输入参数引起的,则抛出异常(但这些通常是未经检查的)【讨论】:
对,第三条规则很清楚。关于以有意义的方式处理异常,这是在程序的更高层吗?这是否意味着 API 通常会抛出异常?另外,在什么情况下,方法应该重新抛出来自子方法(例如来自私有实用程序方法)的异常? 嗯,这在很大程度上取决于。 API 抛出异常,是的。但随之而来的是选中与未选中的选择。 为什么要重新抛出异常?只是不要抓住它并将其传递到调用堆栈。【参考方案2】:一般来说,当一个方法不能在本地处理相关问题时,它应该向它的调用者抛出一个异常。例如。如果该方法应该从具有给定路径的文件中读取,IOExceptions
不能以合理的方式在本地处理。同样适用于无效输入,并补充说我个人的选择是在这种情况下抛出一个未经检查的异常,如 IllegalArgumentException
。
如果出现以下情况,它应该从被调用的方法中捕获异常:
这是可以在本地处理的东西(例如,尝试将输入字符串转换为数字,如果转换失败,则完全可以返回默认值), 或者它不应该被抛出(例如,如果异常来自特定于实现的较低层,其实现细节不应该对调用者可见 - 例如,我不想显示我的DAO
使用Hibernate
用于持久化我的实体,因此我在本地捕获所有 HibernateExceptions
并将它们转换为我自己的异常类型。
【讨论】:
好的。为了重新制定,当无法立即解决并且需要“上方”进行一些交互来决定要做什么时,将引发异常。此外,如果异常仅在一组类之间具有“含义”,则不会重新抛出异常,并且应该在其位置抛出更通用的异常以通知调用者需要注意。这听起来或多或少是对的吗? @James,或多或少:-) 如果“交互”是指要求用户干预,则并不总是需要。此外,我更喜欢“不同”,而不是“更通用”。用户定义的 ConnectionException 并不比 HibernateException 更通用。【参考方案3】:这是我使用它的方式:
抛出:
您只希望代码在何时停止 发生错误。 适用于容易出现的方法 如果某些先决条件是错误的 没有遇到。Try-Catch:
当你想要程序时 以不同的方式表现不同的 错误。 如果您想提供,那就太好了 对最终用户有意义的错误。我认识很多人总是使用 Throws,因为它更干净,但几乎没有那么多控制。
【讨论】:
您几乎不应该将异常处理用于程序控制。这是一种糟糕的做法。 还有 Try-catch-rethrow 或 try-catch-wrap-throw——也就是说,仅仅因为您可以以有意义的方式处理异常并不意味着您已经完成了。该方法应该按照其名称指示的方式执行操作,或者应该抛出异常:abstractions-r-us.blogspot.com/2010/06/…。 (我博客的无耻插件) 这是一个我一直想知道的问题。我认为如果需要用户定义的异常,我会尝试使用 try-catch 块。例外。但是我不得不说,如果您必须进行任何调试,方法存根中的 throws 会更干净,并且以后需要整理的代码也更少。如果您在方法存根中使用 throws,您必须将错误捕获到方法链中,我认为,这我不确定。使用 try-catch 您可以让 try-catch 捕获错误,而无需将其传递到方法链中。我对此并不完全确定,但我认为 我认为这就是一般情况。我知道通过读取文件,如果您使用 try-catch 然后在另一个类中声明您的类的实例,您不必让该方法抛出异常。我对此仍然不确定。【参考方案4】:我个人的经验法则很简单:
我可以以有意义的方式处理它(从评论中添加)吗?所以把代码放在try/catch
。通过处理它,我的意思是能够通知用户/从错误中恢复,或者更广泛地说,能够理解这个异常如何影响我的代码的执行。
别处,扔掉
注意:此回复现在是一个社区 wiki,请随时添加更多信息。
【讨论】:
我可以以有意义的方式处理它。 您决定是否可以在本地处理异常的标准是什么?这是在您可以实际处理异常并显示消息的级别上吗? 扔掉它是个坏主意。最好将其传递到调用堆栈。【参考方案5】:向您的方法添加 try-catch 或 throws 子句的决定取决于“您希望(或必须)如何处理您的异常”。
如何处理异常是一个广泛且远非微不足道的问题。它特别涉及决定在哪里处理异常以及在 catch 块中执行哪些操作。事实上,如何处理异常应该是一个全局的设计决策。
所以回答你的问题,没有经验法则。
您必须决定要在哪里处理异常,并且该决定通常非常具体地针对您的域和应用程序要求。
【讨论】:
【参考方案6】:如果引发异常的方法有足够多的信息来处理它,那么它应该捕获并生成有关发生的事情和正在处理的数据的有用信息。
【讨论】:
您是否总是将错误异常写入记录器文件或控制台。昨晚我正在考虑这个问题,因为在实际程序中您将无法看到实际的控制台,所以您的错误不应该转到文本文件。那么 e.printStackTrace() 是如何打印的。调试时我会进入控制台,但还能去吗?【参考方案7】:一个方法应该只throws
一个异常,如果它可以围绕对象的状态、传递给方法的任何参数以及该方法作用的任何其他对象做出合理的保证。例如,应该从集合中检索调用者期望包含在其中的项目的方法可能throws
如果期望存在于集合中的项目不存在,则检查异常。捕获该异常的调用者应该期望该集合不包含有问题的项目。
请注意,虽然 Java 将允许通过声明为抛出适当类型的异常的方法冒出已检查的异常,但这种用法通常应被视为反模式。例如,假设某个方法LookAtSky()
被声明为调用FullMoonException
,并期望在满月时抛出它;进一步想象,LookAtSky()
调用ExamineJupiter()
,它也被声明为throws FullMoonException
。如果FullMoonException
被ExamineJupiter()
抛出,并且如果LookAtSky()
没有捕获它并处理它或将其包装为其他异常类型,则调用LookAtSky
的代码将假定异常是由于地球的月亮满了;它不会知道木星的一颗卫星可能是罪魁祸首。
调用者可能期望处理的异常(基本上包括所有检查的异常)只有在异常对方法调用者的意义与对被调用方法的意义相同的情况下才允许通过方法向上渗透。如果代码调用了一个声明为抛出一些已检查异常的方法,但调用者并不期望它在实践中抛出该异常(例如,因为它认为它预先验证了方法参数),则应捕获并包装已检查异常在一些未经检查的异常类型中。如果调用者不期望抛出异常,则调用者不能期望它具有任何特定含义。
【讨论】:
【参考方案8】:什么时候用什么。我对此进行了很多搜索。 没有硬性规定。
“但是作为开发人员,检查的异常必须包含在方法的 throws 子句中。这是编译器知道要检查哪些异常的必要条件。 按照惯例,未经检查的异常不应包含在 throws 子句中。 包括它们被认为是糟糕的编程实践。编译器将它们视为 cmets,并且不对它们进行检查。”
资料来源:Kathy Sierra 的 SCJP 6 书
【讨论】:
【参考方案9】:我会为您简化。 当你认为被调用的方法不对异常负责时使用 throws(例如,来自调用者方法的无效参数、要搜索的项目、在集合中不可用的获取或获取数据列表)。 当您认为您在被调用方法中的功能可能导致某些异常时,请使用 try catch 块(处理被调用方法中的异常)
【讨论】:
【参考方案10】:如果你使用try catch,当异常发生时,剩余的代码仍然会被执行。
如果你指明抛出异常的方法,那么当异常发生时,代码将立即停止执行。
【讨论】:
【参考方案11】:当您想提供自定义行为时使用try-catch 对,以防万一发生异常.....换句话说...您可以根据程序要求解决问题(发生异常)。 ....
但是当您对异常发生情况没有任何具体解决方案时使用 throws...您只是不想让程序异常终止....
希望它是正确的:-)
【讨论】:
以上是关于投掷或尝试接住的主要内容,如果未能解决你的问题,请参考以下文章
CollapsingToolbarLayout 无法识别滚动投掷
Spring 5 MVC Angular 5 App投掷404错误