扔或不扔

时间:2010-03-25 11:51:27

标签: language-agnostic exception-handling

//
// To Throw
void PrintType(object obj)
{
    if(obj == null) 
    {
        throw new ArgumentNullException("obj")
    }
    Console.WriteLine(obj.GetType().Name);    
}

//
// Not to Throw
void PrintType(object obj)
{
    if(obj != null)
    {
        Console.WriteLine(obj.GetType().Name);
    }
}

要保留什么原则?

就我个人而言,我更喜欢 开发人员友好型 (通知每个“异常”)。 第二个说它 用户友好 (让用户继续工作,即使“内部”并非一切正常)。

我认为,当您默默地让事情继续下去时,在维护阶段发现错误和错误会更复杂。如果出现问题,您不会立即得到通知,有时会出现远离主要错误原因的错误,并花费大量时间来查找错误。

您怎么看?

14 个答案:

答案 0 :(得分:33)

第二个是致命的。静默失败是始终错误的事情。假设这是持有您帐户的银行中的银行系统。如果支付你的工资有问题并且系统默默地忽略它,你会喜欢它吗?

答案 1 :(得分:7)

如果方法体正确处理null obj(换句话说,obj!= null不是必需的),那么就不需要抛出异常。

在所有其他情况下:投掷。让客户对他们有缺陷的意见负责。

答案 2 :(得分:4)

抛出异常(如果null是错误)似乎远比忽略错误要好得多。

您可以考虑第三种选择:

void PrintType(object obj)
{
    Console.WriteLine(obj.GetType().Name);
}

当obj为null时,这也会抛出异常。这样做的好处是涉及的代码更少。这种方法的缺点是更难以判断obj是否为空。

答案 3 :(得分:3)

投掷。

让函数的调用者确定它是否足够重要,以便在空值上向用户抛出异常,但函数本身应该因为无效参数而抛出。

答案 4 :(得分:1)

我会说这取决于您(开发者)的偏好。从用户的角度来看,他永远不应该看到未处理的异常,但这并不意味着你不能使用异常。

我更喜欢第一个,因为我发现null是一个完全不必要(且令人讨厌)的构造,所以我努力在没有它的情况下进行编码。如果某个地方有一个null,那么有人犯了一个错误,所以最好的办法就是禁止一切,而不是假装一切正常。

最后,它取决于您认为是该方法的语义。如果该方法应该接受空值,那么你应该选择第二个选项。如果该方法只能接受真实的参数(我更喜欢),那么你应该选择第一个选项。

答案 5 :(得分:1)

始终在调试/诊断代码中抛出。在生产代码中出现NullPointerException是最令人尴尬的,因为在这一点上只应生成调试消息,例如。

log.debug("id of object is " + obj.getId())

关闭记录器,obj为空。

答案 6 :(得分:1)

这是非常主观的,但我总是喜欢忽略非致命或可恢复的错误。如果必须,请将它们放入日志中,但如果您知道如何继续 - 请执行此操作。

注意,当我说致命时,它实际上取决于功能本身。比方说,有API函数可以获取ID和其他一些参数。假设,这个ID也可以从传入的其他东西中猜到.API函数应该猜测它是否可以,但是内部的函数可以完成所有工作应该获得非空ID,否则抛出。因为对于高级API函数它不是致命的,它知道如何猜测它,但对于低级函数它是致命的,它应该用该ID执行某些操作并且使用null值它无法继续。

当然,应注意所有致命错误。

答案 7 :(得分:1)

如果api暴露在外面,请始终进行参数检查并抛出基于参数的异常,以便api用户可以得到结果。

答案 8 :(得分:0)

考虑使用Null Object pattern非常有用,不会使用try-catch,null检查(或者上帝禁止吞下错误)来混淆你的代码。

答案 9 :(得分:0)

在这个特定的例子中,什么都不给打印机就像是说“什么都不打印”,因此可以正常工作。

我知道这是一个例子,但这只是为了澄清这是相对的。

如果您的代码以某种方式显示有关例外的用户友好消息,它会有什么不同?第一个是开发人员和用户友好的。

答案 10 :(得分:0)

这实际上取决于你的不变量。如果参数是optiona,那么忽略 null 参数就可以了,但如果参数是必需的,那么这将隐藏应用程序中的错误。此外,根据语言,如果不变量足够糟糕,您可以考虑第三种选择:中止应用程序。

关于是否使用例外的所有讨论总是可以映射到关于情况是否异常的决定,如果是例外,抛出或者反而中止应用程序取决于是否它是可以恢复的。

答案 11 :(得分:0)

我想去

void PrintType(object obj) {     Console.WriteLine(obj.GetType()名称。); }

答案 12 :(得分:0)

第三个选项,一半是伪代码:

// To Throw A Clean Error
void PrintType(object obj)
{
    if(obj == null) 
    {
        throw new ArgumentNullException(STANDARD_ERROR_MESSAGE, obj)
    }

    Console.WriteLine(obj.GetType().Name);    
}

捕获所有错误并将它们包装在一个地方,以便用户看到标准文本:

  

出现了错误。如果这个错误   坚持,请联系   管理员。

或抛出一些精选的错误,所有错误都是用户友好的,并直接显示给用户。 “发生连接错误。” “发生了身份验证错误。” “发生了系统错误。”等等。

在后端,记录所有错误及其堆栈跟踪,以便您可以通过这种方式使用调试信息。

答案 13 :(得分:0)

这实际上取决于定义的功能。最重要的方面是有一个明确定义的行为,以及正确实现它的功能。

现在,如果问题是定义函数是否更好以接受null并将其打印出来,或者不接受它并抛出异常,我会说后者,因为它可能不太容易让用户感到错误在调用函数之前检查null,如果可能的话。