如果一个检索方法返回“null”,或者当它不能产生返回值时抛出exception?
我有一个方法,应该返回一个对象,如果它被发现。
如果没有find,我应该:
- 返回null
- 抛出exception
- 其他
如果你总是期待find一个值,那么抛出exception,如果它是缺less的。 例外将意味着有一个问题。
如果该值可能缺失或存在,并且两者都对应用程序逻辑有效,则返回null。
更重要的是:你在代码中的其他地方做了什么? 一致性很重要。
只有在发生错误时才抛出exception。 如果预期该对象的行为不存在,则返回null。
否则,这是一个偏好的问题。
作为一般规则,如果该方法应该总是返回一个对象,那就去例外。 如果您预计偶尔会出现null,并希望以某种方式处理它,请使用null。
无论你做什么,我强烈build议不要第三个选项:返回一个string,说“WTF”。
如果null从不指示错误,则返回null。
如果null总是一个错误,那么抛出一个exception。
如果null有时是一个exception,那么就编写两个例程。 一个例程抛出一个exception,另一个例程是一个布尔testing例程,返回输出参数中的对象,如果找不到对象,例程返回false。
很难误用Try例程。 忘记检查null是很容易的。
所以当null是一个错误,你只是写
object o = FindObject();
当null不是一个错误,你可以编写类似的东西
if (TryFindObject(out object o) // Do something with o else // o was not found
我只是想概括一下前面提到的select,在一些新的方面抛出:
- 返回null
- 抛出一个exception
- 使用空对象模式
- 给你的方法提供一个布尔参数,所以调用者可以select,如果他希望你抛出一个exception
- 提供一个额外的参数,所以如果没有find值,调用者可以设置一个他返回的值
或者你可以结合这些选项:
提供你的getter的几个重载版本,所以调用者可以决定走哪条路。 在大多数情况下,只有第一个实现了searchalgorithm,其他的只是围绕第一个:
Object findObjectOrNull(String key); Object findObjectOrThrow(String key) throws SomeException; Object findObjectOrCreate(String key, SomeClass dataNeededToCreateNewObject); Object findObjectOrDefault(String key, Object defaultReturnValue);
即使你select只提供一个实现,你可能也想使用这样的命名约定来阐明你的合同,并且它也可以帮助你决定添加其他的实现。
你不应该过度使用它,但是当编写一个辅助类的时候,它可能是有用的,你将在数百个不同的应用程序中使用它,并且有许多不同的error handling约定。
使用空对象模式或抛出exception。
与您使用的API保持一致。
只要问自己:“这是一个例外的情况下,没有发现的对象”? 如果预计会发生在你的程序的正常过程中,你可能不应该提出exception(因为它不是例外的行为)。
短版本:使用exception来处理exception行为,而不是处理程序中正常的控制stream。
-Alan。
这取决于你的语言和代码是否提倡:LBYL(看你跳跃之前)还是EAFP(比允许更容易要求原谅)
LBYL说你应该检查值(所以返回一个null)
EAFP说,只是尝试操作,看看是否失败(抛出一个例外)
虽然我同意上面的例外应该用于例外/错误的条件,返回null是最好的时候使用检查。
Python中的EAFP与LBYL:
http://mail.python.org/pipermail/python-list/2003-May/205182.html(Web Archive )
我宁愿只返回一个null,并依靠调用者来适当地处理它。 (缺less一个更好的词)exception是如果我绝对“确定”这个方法将返回一个对象。 在这种情况下,失败是一个例外,应该抛出。
取决于什么意思是没有find该对象。
如果是正常情况,则返回null。 这只是偶尔会发生的事情,打电话的人应该检查一下。
如果是错误,则抛出exception,调用者应该决定如何处理丢失对象的错误状态。
最终,两者都可以工作,尽pipe大多数人普遍认为只有在出现exception情况时才使用exception。
例外与devise合同有关。
对象的接口实际上是两个对象之间的契约,调用者必须符合合同,否则接收者可能会失败并产生exception。 有两个可能的合同
1)所有input的方法是有效的,在这种情况下,如果找不到对象,则必须返回null。
2)只有一些input是有效的,即导致find的对象。 在这种情况下,您必须提供第二种方法,允许调用者确定其input是否正确。 例如
is_present(key) find(key) throws Exception
IF和ONLY如果你提供第二个合同的两种方法,你被允许抛出一个exception是没有什么被发现的!
抛出exception的优点:
- 清洁控制stream程在您的调用代码。 检查null注入try / catch本地处理的条件分支。 检查为null并不表明你正在检查什么 – 你是否检查null,因为你正在寻找一个你期望的错误,或者你检查为空,所以你不会进一步传递下链?
- 消除“null”含义的模糊性。 是null代表一个错误,或者为null实际存储在值中? 很难说什么时候你只有一件事情要做出决定。
- 改进应用程序中方法行为之间的一致性。 exception通常在方法签名中公开,所以您可以更好地理解应用程序中的方法所涉及的边界情况,以及您的应用程序可以以可预测的方式应对哪些信息。
有关示例的更多解释,请参阅: http : //metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/
在一些函数中,我添加了一个参数:
..., bool verify = true)
True表示抛出,false表示返回一些错误返回值。 这样,使用这个function的人有两种select。 默认值应该是真实的,为忘记error handling的人的好处。
返回null而不是抛出一个exception,并清楚地loggingAPI文档中返回空值的可能性。 如果调用代码不符合API并检查为空的情况,那么最有可能导致某种“空指针exception”:)
在C ++中,我可以想到3种不同的风格来设置一个find对象的方法。
选项A
Object *findObject(Key &key);
无法find对象时返回null。 好而简单。 我会去这个。 下面的替代方法适用于不讨厌超参数的人。
选项B
void findObject(Key &key, Object &found);
传入将要接收对象的variables的引用。 当找不到对象时,该方法抛出exception。 这个约定可能更合适,如果它不是一个真正的预期不会find一个对象 – 因此你抛出一个exception,以表示这是一个意外的情况。
选项C
bool findObject(Key &key, Object &found);
当找不到对象时,该方法返回false。 这比选项A的优点是你可以在一个清晰的步骤中检查错误情况:
if (!findObject(myKey, myObj)) { ...
这里有几个build议。
如果返回一个集合,避免返回null,返回一个空的集合,使枚举更容易处理,而不先检查null。
几个.NET API使用thrownOnError参数的模式,给调用者提供select,如果没有find该对象,那么是否真的是exception情况。 Type.GetType就是一个例子。 BCL的另一个常见模式是TryGet模式,其中返回一个布尔值,并通过输出parameter passing值。
在某些情况下,你也可以考虑Null对象模式,它可以是默认的,也可以是没有行为的版本。 关键是避免在整个代码库中进行空值检查。 在这里查看更多信息http://geekswithblogs.net/dsellers/archive/2006/09/08/90656.aspx
只提到空值不被视为例外行为的情况下,我肯定是尝试方法,很明显,没有必要像在这里所说的那样“阅读本书”或“看看你跳跃之前”
所以基本上:
bool TryFindObject(RequestParam request, out ResponseParam response)
这意味着用户的代码也将清晰
... if(TryFindObject(request, out response) { handleSuccess(response) } else { handleFailure() } ...
如果客户端代码知道发现与未发现之间的区别很重要,并且这应该是一个常规行为,那么最好返回null。 客户端代码可以决定要做什么。
通常它应该返回null。 调用方法的代码应该决定是抛出一个exception还是尝试别的。
或者返回一个选项
一个选项基本上是一个强制客户端处理展台的容器类。 斯卡拉有这个概念,查找它的API。
然后在这个对象上有像T getOrElse(T valueIfNull)这样的方法返回find的对象,或者是客户端指定的全选。
只要它应该返回对象的引用 ,返回NULL应该是好的。
但是,如果它返回的是整个血腥的事情(比如在C ++中,如果你这么做的话:'return blah;'而不是'return&blah;'(或'blah'是一个指针),那么你不能返回NULL,因为而不是“对象”types,在这种情况下,抛出一个exception,或者返回一个没有设置成功标志的空白对象就是我如何处理这个问题。
不要以为任何人都提到了exception处理的开销 – 需要额外的资源来加载和处理exception,所以除非它的真正的应用程序杀死或进程停止事件(前进会造成更多的伤害,而不是好),我会select传回呼叫环境可以解释它认为合适的价值。
我同意这里似乎是共识(如果“未find”是一个正常的可能结果,则返回null,如果情况的语义要求始终find该对象,则返回一个exception)。
然而,根据你的具体情况,第三种可能性是有意义的。 你的方法可以在“not found”条件下返回某种types的默认对象,这样可以保证调用代码在不需要空值检查或exception捕获的情况下总能得到一个有效的对象。
返回null,exception就是这样:你的代码做的事情不是预期的。
例外情况应该是例外 。 如果有效返回null ,则返回null 。
更喜欢返回null –
如果调用者没有检查就使用它,反正就会发生exception。
如果调用者没有真正使用它,不要给他一个try
/ catch
块
不幸的是JDK是不一致的,如果你试图访问资源包中的非现有密钥,你不会发现exception,并且当你从map请求值时,如果它不存在,则返回null。 所以我会改变赢家回答以下,如果发现值可以为空,然后提出exception,当它没有find,否则返回null。 所以遵循规则有一个例外,如果你需要知道为什么没有find价值,那么总是引发exception,或..
如果方法返回一个集合,则返回一个空集合(如上所述)。 但请不要Collections.EMPTY_LIST或这样的! (在Java的情况下)
如果方法回顾一个单一的对象,那么你有一些select。
- 如果方法应该总是find结果,并且它是一个真正的exception情况下不find对象,那么你应该抛出一个exception(在Java中:请一个未经检查的exception)
- (仅限Java)如果您可以容忍该方法抛出一个检查的exception,则抛出一个特定于项目的ObjectNotFoundException或类似的东西。 在这种情况下,编译器会说你是否忘记处理exception。 (这是我在Java中找不到的东西的首选处理。)
- 如果你说它确实没问题,如果找不到对象,你的方法名称就像findBookForAuthorOrReturnNull(..),那么你可以返回null。 在这种情况下, 强烈build议使用某种静态检查或编译器检查,以防止在不进行空检查的情况下取消引用结果。 在Java的情况下,它可以是例如。 FindBugs(请参阅http://findbugs.sourceforge.net/manual/annotations.html上的; DefaultAnnotation)或IntelliJ-Checking。
要小心,如果你决定返回一个null。 如果你不是项目中唯一的程序员,你将在运行时得到NullPointerExceptions(用Java或其他语言)! 所以不要返回在编译时不检查的空值。
如果您正在使用库或引发exception的其他类,则应该重新抛出它。 这是一个例子。 Example2.java就像库,Example.java使用它的对象。 Main.java是处理这个exception的例子。 您应该向主叫方显示一条有意义的消息和(如果需要的话)堆栈跟踪。
Main.java
public class Main { public static void main(String[] args) { Example example = new Example(); try { Example2 obj = example.doExample(); if(obj == null){ System.out.println("Hey object is null!"); } } catch (Exception e) { System.out.println("Congratulations, you caught the exception!"); System.out.println("Here is stack trace:"); e.printStackTrace(); } } }
Example.java
/** * Example.java * @author Seval * @date 10/22/2014 */ public class Example { /** * Returns Example2 object * If there is no Example2 object, throws exception * * @return obj Example2 * @throws Exception */ public Example2 doExample() throws Exception { try { // Get the object Example2 obj = new Example2(); return obj; } catch (Exception e) { // Log the exception and rethrow // Log.logException(e); throw e; } } }
Example2.java
/** * Example2.java * @author Seval * */ public class Example2 { /** * Constructor of Example2 * @throws Exception */ public Example2() throws Exception{ throw new Exception("Please set the \"obj\""); } }
这真的取决于你是否期望find对象,或不。 如果你遵循这样一种思想,那就是例外应该用来表示某种东西,那么,就会发生例外:
- find对象; 返回对象
- 对象未find; 抛出exception
否则,返回null。