正常程序逻辑和异常

时间:2012-09-27 14:11:50

标签: java exception

我正在审核一些团队代码,我发现了类似的内容:

MyObj obj = null;

try {
  obj = myService.findObj(objId)
} catch (MyObjNotFoundException e) {
  // The object wasn't found, it's the "normal" path
  // Here they create the object in DB (but don't touch the obj variable)
  // There is about 60 line of code
}
if (obj != null) {
  // The object already exist, logs are written and some queue is filled
  // with current objId to be processed later on
}

在我的评论中,我会写一下,在性能或可维护性方面,使用Exception来控制正常的程序流并不是一个好主意。 最好的方法是修改服务以返回null而不是抛出异常但是:

  • 我不确定他们是否拥有该服务(可能是另一个项目/团队)
  • 他们可能在其他地方确实需要此例外

除了不抛出Exception之外不会解决的性能问题,我想给他们一个“更干净”的代码。

以下是我的想法,知道该服务只发送此例外:

try {
  obj = myService.findObj(objId)
} finally {
}

if (obj == null) {
  // The object wasn't found, it's the "normal" path
} else {
  // The object already exist, logs are written and some queue is filled
  // with current objId to be processed later on
}
你会这样走吗? 它是否真正迈向可读性? 你还会想到其他什么吗?

非常感谢。

6 个答案:

答案 0 :(得分:2)

在您的建议中,如果服务抛出ObjectNotFoundException,您的方法也会这样做。在不改变服务签名的情况下,代码当前所做的只是唯一的方法。

或许你的意思是

try {
    obj = myService.findObj(objId)
} 
catch (ObjectNotFoundException) {
    // ignore, obj stays null
}

if (obj == null) {
    // The object wasn't found, it's the "normal" path
} 
else {
    // The object already exist, logs are written and some queue is filled
    // with current objId to be processed later on
}

这与当前代码非常相似。在任何情况下,为了使代码更清晰,应该做些什么,将正常路径的60行代码提取到另一个方法中,本身在几个子方法中分离。

答案 1 :(得分:1)

就个人而言,我认为你的改变根本不会产生任何重大影响。也许对Java字节优化有更好了解的人可以插入,但我希望异常处理的额外“权重”仍然内置,即使异常块中没有任何内容。

避免将异常处理用作流控制的一个最大原因是由于抛出异常的代价。编译器不是为优化异常处理而设计的;他们希望它们只在特殊情况下抛出(原谅双关语) - 即:当应用程序遇到意外情况时。因此,所有重点都放在优化标准流控制逻辑上(if / else,for,while等等)。从可读性角度和性能角度来看,使用流控制异常是一个糟糕的想法。

找不到对象不是意外情况。实际上,它是在开发代码之前应该设计的逻辑/流程图的一部分,并根据预期结果记录正确的返回值。数据库响应失败将是一个可接受的异常情况 - 这种情况很少发生,而且确实是一种意外状态。

基本上,在我看来,你提出的改变使得阅读变得更加复杂。问题的核心是被抛出的例外。如果这无法弥补,我不相信你的空尝试/捕获确实有很大帮助。如果有的话,你的代码首先说你打算忽略所有未找到的异常,但是稍后,你选择处理它,这有点矛盾。如果从中获得了性能提升,那将是我理解的,但就像我说的那样,我相信最昂贵的部分是抛出异常,而不是实际捕获它。

答案 2 :(得分:1)

Exception非常适用于逻辑经常做一些预期不会出现在运行良好的系统中的东西。 例如,每个Person对象必须有一个firstname。 不包含一个名字的人是一个特殊的东西,必须使用Exception来处理。

相反,使用null表示情况“正常”但没有显着结果。为了保持相同的例子,一个人可能有两个名字,但它确实是可选的。在这种情况下,名为retrieveSecondFirstName()的概念方法将有效地返回null

我更喜欢在适应时使用Null Pattern。 看http://en.wikipedia.org/wiki/Null_Object_pattern

此外,投掷Exception或使用Null Pattern可避免客户端NullPointerExcetion的典型情况。

答案 3 :(得分:0)

我喜欢使用异常而不是返回null,因为您可以将出现错误的原因传递给用户。从我的角度来看,它比返回null更好。

答案 4 :(得分:0)

没有正确或错误的方法来做到这一点。我只能告诉你,自J2EE和EJB 2.0早期以来, ObjectNotFoundException - 模式已经存在。抛出FinderException的子类是很常见的,当时一个典型的业务逻辑涉及捕获大约17亿个恼人的检查异常,只是为了将大部分内容包装在RuntimeExceptions中以便能够将它们重新抛入涅。

如今,返回null可能会再次变得更受欢迎,因为无论如何找不到对象都不是一个例外,而null恰恰具有这种语义。除此之外,null并不比ObjectNotFoundException好。只是品味问题。

答案 5 :(得分:0)

没有明确的答案,这取决于findObj()的工作方式。在大多数情况下它会返回一个对象吗?如果找不到对象,这是一种特殊的情况,是不是出乎意料的事情?我想不是在这种情况下,我会在这里返回null。基于异常的版本更难以阅读和维护。