1

我正在审查一些团队代码,我发现了这样的东西:

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而不是抛出异常但是:

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

所以除了除非不抛出异常否则无法解决的性能问题,我想给他们一个“更干净”的代码。

这是我知道服务仅发送此异常的想法:

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
}

你会走这条路吗?它真的在可读性上迈出了一步吗?你会想点别的吗?

非常感谢。

4

6 回答 6

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 行代码提取到另一个方法中,该方法本身分为几个子方法。

于 2012-09-27T14:20:26.040 回答
1

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

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

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

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

于 2012-09-27T14:20:02.217 回答
1

Exception当逻辑经常做一些不希望出现在运行良好的系统中的事情时,这是非常适合的。例如,每个Person对象必须有一个firstname. 一个不包含一个名字的人是一个例外的事情,必须使用Exception.

相反,用于null表示情况“正常”但不涉及重大结果。为了保持同样的例子,一个人可能有两个名字,但它实际上是可选的。在这种情况下,一个名为的概念方法retrieveSecondFirstName()将有效地返回。null

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

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

于 2012-09-27T14:21:05.630 回答
0

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

于 2012-09-27T14:14:58.280 回答
0

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

如今,返回null可能会再次变得更流行,因为无论如何找不到对象并不是这样的例外,并且null恰好具有这种语义。除此之外,null并不比ObjectNotFoundException. 只是口味问题。

于 2012-09-27T14:18:08.253 回答
0

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

于 2012-09-27T14:31:28.513 回答