什么时候可以对业务逻辑使用exception处理?

我认为可以接受的是,作为Java中的一般规则(也许是任何具有exception处理的语言),应该尽量避免使用exception处理来实际处理业务逻辑。 一般来说,如果预计会发生某种情况,那么应该检查它并直接处理它,而不是依赖于exception处理来为您进行检查。 例如,以下不被视为良好做法:

try{ _map.put(myKey, myValue); } catch(NullPointerException e){ _map = new HashMap(); } 

相反,延迟初始化应该更像这样:

 if(_map == null){ _map = new HashMap(); } _map.put(myKey, myValue); 

当然,可能存在比简单处理延迟初始化更复杂的逻辑。 因此,鉴于此类事情通常不受欢迎……如果有的话,依赖于某些业务逻辑发生的exception是一个好主意吗? 是否准确地说任何一个人感到被迫使用这种方法的实例是否真的突出了所使用的API的弱点?

每当exception可以预期但不能避免时。

比方说,如果您依赖某种外部API来解析数据,并且该API提供了解析方法,但没有什么可以判断是否可以解析给定的输入(或者解析是否成功取决于因素)您的控件,但API不提供适当的函数调用),并且解析方法在无法解析输入时抛出exception。

使用设计合理的API,这应该可以归结为“几乎从不”到“从不”范围内的某个数量。

我完全没有理由将exception处理用作代码中正常流控制的方法。 它很昂贵,很难阅读(只看你自己的第一个例子;我意识到它可能写得很快,但是当_map尚未初始化时,你最终得到的是一张空地图,扔掉你的条目试图添加),它使用大量无用的try-catch块来填充代码,这可以很好地隐藏真正的问题。 再举一个你自己的例子,如果对_map.add()的调用因为_mapnull某些原因而抛出NullPointerException怎样? 突然间,您正在静默地重新创建一个空地图,而不是添加一个条目。 我确信我不必说,由于意外的状态,可能导致代码中完全不相关的地方出现任意数量的错误……

编辑:为了清楚起见,上面的答案是在Java的上下文中编写的。 其他语言可能(并且显然,确实)在exception的实现费用方面有所不同,但其他方面仍应保留。

抛出exception是C ++中相对昂贵的操作,而且在Java中是非常昂贵的操作。 仅从效率的角度来看,避免明确检查并接受exception是没有意义的。 我想你可能能够在极少数情况下certificate它是合理的,在这种情况下,检查是否会抛出exception是非常复杂或几乎不可能的,但除此之外,我会说答案是“几乎从来没有”。

这实际上是一个讨论问题,答案取决于系统的设计。

我的直觉总是永远不会,但我看到有几个系统使用exception来实现业务错误。 我个人觉得这很令人作呕,但我真的理解一旦你知道它失败了,打破业务流程的优势,处理你的失败(例如回滚你的工作单元),并将错误返回给调用者,也许是添加了信息。

一个可能的缺点是,跨多个不同的类进行error handling非常简单,因此在进程失败时发生的事情的定义很难从代码中推断出来。

无论如何,这里没有单一的答案,你需要权衡两种方法,有时将它们结合起来。

关于您的示例,我认为使用流控制exception没有任何优势,特别是在“良好”(旨在工作)的情况下。

有exception是对象的原因。 Java语言的设计者还将所有Throwable分为两种主要类型:checked和unchecked。

依赖某些业务逻辑发生的exception是一个好主意吗?

是。 绝对。 您应该阅读“Effective Java,Second Edition”的第9章 。 一切都在那里。 很好地解释和等你。

如果您正在处理实际上是业务逻辑一部分的错误条件,则可以使用Exceptions。 例如:

 try{ // register new user if(getUser(name) != null) throw new MyAppException("Such user already exists"); //other registration steps...... }catch(MyAppException ex){ sendMessage(ex.getMessage()); }