抛出或尝试接球


77

决定是在方法中添加throws子句还是使用try-catch?的一般经验法则是什么?

根据我自己的了解,throws当调用方破坏了合同的末端(传递的对象)时,try-catch应使用;当在方法内部执行的操作期间发生异常时,应使用。它是否正确?如果是这样,应该在呼叫方执行什么操作?

PS:通过Google和SO搜索,但希望对此有一个明确的答案。


4
我一直都是“如果在这里处理它的话……那就去做”的方法。
CheesePls

我希望所有异常都在发生的地方得到处理,这样我就不必处理后续的工作了。
Doug Hauf 2014年

Answers:


58
  • 仅在您可以以有意义的方式处理异常时才捕获异常
  • 如果要由当前方法的使用者处理,则声明向上抛出异常
  • 如果它们是由输入参数引起的,则抛出异常(但是通常不检查这些异常)

是的,第三条规则很明确。关于以有意义的方式处理异常,这是否在程序的更高层中?这是否意味着API通常会引发异常?此外,在什么情况下,方法应该重新抛出来自子方法的异常(例如,来自私有实用程序方法的异常)?
James P.

好吧,这在很大程度上取决于。API会引发异常,是的。但是,随之而来的是选中还是未选中。
博佐

3
为什么要抛出异常?只是不要抓住它并将其传递给调用堆栈。
郭富城2010年

15

通常,当方法无法在本地处理关联的问题时,该方法应向其调用方抛出异常。例如,如果该方法应该从具有给定路径的文件中读取,IOExceptions则不能以明智的方式在本地进行处理。对于无效输入,同样适用,并补充说,我个人的选择是像IllegalArgumentException在这种情况下一样抛出未经检查的异常。

并且它应该在以下情况下从调用的方法中捕获异常:

  • 它是可以在本地处理的(例如,尝试将输入字符串转换为数字,如果转换失败,则返回默认值是完全有效的),
  • 还是不应该抛出该异常(例如,如果异常来自特定于实现的较低层,则其实现细节对于调用者而言应该是不可见的,例如,我不想表明用于持久化实体的DAO用途Hibernate,因此我HibernateExceptions在本地捕获所有内容并将它们转换为我自己的异常类型)。

好。要进行重新表述,当不可能立即解决并且需要“上方”进行某些交互来决定要做什么时,将引发异常。另外,如果异常在一组类之间仅具有“含义”,并且不会抛出异常,则应该在该位置抛出更笼统的异常,以通知调用者需要引起注意。这听起来或多或少正确吗?
James P.

1
@James,或多或少:-)如果通过“交互”是指要求用户干预,则并非总是需要。另外,我更喜欢“不同”而不是“更广义”。用户定义的ConnectionException不比HibernateException更通用。
彼得Török

11

这是我的使用方式:

抛出:

  • 您只希望代码在发生错误时停止。
  • 如果某些先决条件得不到满足,则很容易出错。

试着抓:

  • 当您想让程序表现不同时出现不同的错误。
  • 如果您想向最终用户提供有意义的错误,那就太好了 。

我知道很多人经常使用Throws,因为它更干净,但控制权却不那么多。


您几乎永远不要将异常处理用于程序控制。这是一种可怕的做法。
CheesePls

2
还有try-catch-ththrow或try-catch-wrap-throw —即仅仅因为您可以以有意义的方式处理异常并不意味着您已经完成。该方法应该执行其名称所指示的操作,或者应该引发异常:abstractions-r-us.blogspot.com/2010/06/…。(我博客的无耻插件)
jyoungdev

1
这是我一直想知道的一个问题。我认为如果需要,可以尝试使用try-catch块以及用户定义的异常。例外。但是我不得不说,方法存根中的抛出会更干净,并且如果您必须进行任何调试,则以后需要排序的代码也更少。如果您在方法存根中使用throws,则必须在方法链中捕获错误,我认为,我不确定。使用try-catch可以使try-catch捕获错误,而不必将错误传递给方法链。我对此并不完全确定,但是我想
Doug Hauf 2014年

我认为,通常情况就是这样。我知道通过读取文件,如果您使用try-catch然后在另一个类中声明您的类的实例,则不必让该方法引发异常。我对此仍然不确定。
Doug Hauf 2014年

9

我个人的经验法则很简单:

  • 我可以以有意义的方式处理它(从注释中添加)吗?所以把代码放进去try/catch。通过处理它,我的意思是能够通知用户/从错误中恢复,或者从更广泛的意义上讲,能够理解该异常如何影响我的代码的执行。
  • 在其他地方,扔掉

注意:此回复现在是社区Wiki,请随时添加更多信息。


6
我能以有意义的方式处理它吗?
Nivas 2010年

2
决定是否可以在本地处理异常的标准是什么?这是您实际上可以处理异常并显示一条消息的级别吗?
James P.

扔掉它是一个坏主意。更好的方法是将其传递给调用堆栈。
史蒂夫·郭

3

向您的方法中添加try-catch或throws子句的决定取决于“您希望(或具有)如何处理异常”。

如何处理异常是一个广泛且遥不可及的问题。它特别涉及决定在哪里处理异常以及在catch块内要执行哪些操作的决定。实际上,如何处理异常应该是全局设计决策。

因此,回答您的问题没有经验法则。

您必须决定要在哪里处理异常,并且该决定通常非常特定于您的域和应用程序要求。


2

如果引发异常的方法有足够的信息要处理,那么它应该捕获并生成关于发生了什么以及正在处理哪些数据的有用信息。


您是否总是将错误异常写入记录器文件或控制台。我昨晚在想这件事,因为在实际程序中您将无法看到实际的控制台,因此您不应将错误输入文本文件。那么e.printStackTrace()如何打印。调试时我进入控制台,但是还能去吗?
Doug Hauf 2014年

1

如果方法throws可以合理地保证对象的状态,传递给该方法的任何参数以及该方法所作用的任何其他对象,则该方法应该只有一个例外。例如,如果从集合中检索调用者希望包含在其中throws的项目,则该方法可能会检查异常,如果预期存在于集合中的项目则不会。捕获到该异常的调用者应期望该集合不包含所讨论的项目。

请注意,尽管Java将允许经过检查的异常通过声明为适当类型的抛出异常的方法冒泡,但通常应将这种用法视为反模式。例如,想象一下,某个方法LookAtSky()被声明为call FullMoonException,并且有望在月球满时抛出该方法;进一步想象一下,该LookAtSky()调用ExamineJupiter()也称为throws FullMoonException。如果aFullMoonException被抛出ExamineJupiter(),并且LookAtSky()没有捕获并处理它或将其包装在其他异常类型中,则所调用的代码LookAtSky将假定该异常是地球满月的结果。根本不知道木星的一颗卫星可能是罪魁祸首。

如果异常对方法的调用方意味着与被调用方法相同的含义,则仅应允许调用方期望处理的异常(包括基本上所有检查的异常)通过方法渗透。如果代码调用的方法声明为抛出某些已检查的异常,但是调用者不希望它在实践中抛出该异常(例如,因为认为它已预先验证了方法参数),则应捕获并包装已检查的异常在某些未经检查的异常类型中。如果调用者不希望引发异常,则调用者不能指望它具有任何特殊含义。


1

什么时候用什么。我对此进行了很多搜索。没有硬性规定。

“但是作为开发人员,Checked异常必须包含在方法的throws子句中。这对于编译器知道要检查哪些异常是必要的。按照惯例,未经检查的异常不应包含在throws子句中。
考虑将它们包括在内会成为不良的编程习惯。编译器会将其视为注释,并且不对其进行检查。”

资料来源:Kathy Sierra撰写的SCJP 6书


0

如果使用try catch,则在发生异常时,其余代码仍将执行。

如果您指示抛出异常的方法,则当发生异常时,代码将立即停止执行。


0

如果要提供自定义行为,则使用try-catch对,以防万一发生异常……换句话说,……根据程序要求,可以解决问题(出现异常)……。 。

但是,当您对异常发生情况没有任何特定的解决方案时,便会使用throws。

希望它是正确的:-)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.