Language agnostic 什么时候处理空指针/引用异常比执行空检查更可取?

Language agnostic 什么时候处理空指针/引用异常比执行空检查更可取?,language-agnostic,exception-handling,null,Language Agnostic,Exception Handling,Null,我有一个奇怪的问题,我一直在想,但从来没有看到它的实际用途。我想看看这是否有足够的理由 什么时候处理空指针/引用异常比执行空检查更可取?如果有的话。 这适用于任何必须处理具有异常处理功能的空指针/引用的语言 对此,我通常的反应是在对指针/引用执行任何操作之前执行空检查。如果为非null,则像正常一样继续并使用它。如果为null,则处理错误或引发错误 i、 e.,(用C#表示) string str=null; 如果(str==null) { //错误! } 其他的 { //做事 int长度=st

我有一个奇怪的问题,我一直在想,但从来没有看到它的实际用途。我想看看这是否有足够的理由

什么时候处理空指针/引用异常比执行空检查更可取?如果有的话。

这适用于任何必须处理具有异常处理功能的空指针/引用的语言

对此,我通常的反应是在对指针/引用执行任何操作之前执行空检查。如果为非null,则像正常一样继续并使用它。如果为null,则处理错误或引发错误

i、 e.,(用C#表示)

string str=null;
如果(str==null)
{
//错误!
}
其他的
{
//做事
int长度=str.长度;
// ...
}
然而,如果我们不进行检查,只是盲目地使用它,就会产生一个例外

string str=null;
int length=str.length;//哦,NullReferenceException
// ...
作为一个例外,我们当然可以抓住它,所以没有什么可以阻止我们这样做(或者有什么?):

string str=null;
尝试
{
int length=str.length;//oops,NullReferenceException
// ...
}
捕获(NullReferenceException ex)
{
//不过没关系,我们现在可以处理了
}
现在我承认,这不是最干净的代码,但它的工作代码也不少,我通常不会这么做。但是,有没有一种设计模式或是一些这样做有用的东西呢?也许比事先直接进行空检查更有用

我能想象的唯一有用的情况是,在多线程环境中,未受保护的共享变量过早设置为null。但这种情况多久发生一次?保护变量的好代码不会有这个问题。或者,如果一个人正在编写一个调试器,并且希望显式抛出异常,只是为了包装它或诸如此类。也许是一种看不见的性能优势,或者是消除了对代码中其他内容的需求


我可能已经回答了我的一些问题,但这样做还有其他用处吗?我不是在寻找“仅仅因为我们可以”这样的例子或写得很差的代码,而是它的实际用途。尽管我同意“它没有实际用途,请检查一下。”

问题是所有空指针异常看起来都很相似。任何可以添加以指示哪个名称触发了异常的记帐都不会比首先检查null更有效。

如果您希望该值不为null,则执行任何检查都没有意义。但是,例如,在接受参数时,测试需要为非null的参数并酌情抛出ArgumentNullExceptions是有意义的

出于两个原因,这是首选的:

  • 通常,您会使用ArgumentNullException构造函数的单字符串形式,传入参数名称。这在调试期间提供了非常有用的信息,因为现在编码人员知道哪个参数为null。如果您的源代码对他们不可用(或者如果异常跟踪是由未安装调试符号的最终用户提交的),则不可能知道实际发生了什么。对于其他异常类型,您还可以指定哪个变量为null,这是非常有用的信息
  • 捕获null解引用是CLR可以执行的最昂贵的操作之一,如果代码抛出大量NullReferenceException,这可能会对性能产生严重影响。测试空值并对其进行其他处理(甚至抛出异常!)是一种更便宜的操作。(类似的原则是,如果您声明catch块的明确目的是捕获nre,那么您在其他地方做了错误的事情,您应该在那里修复它,而不是使用try/catch。捕获nre应该决不能成为任何算法的组成部分。)

  • 这就是说,不要在你不期望空值的地方用空测试来浪费你的代码。但是,如果引用变量可能为null(例如,如果引用是由外部代码提供的),那么您应该始终进行测试。

    我已经为Java编程10多年了,我记不起有一次我明确尝试捕获null指针异常

    有时可能期望变量为null(例如对象的可选属性),在这种情况下,我需要测试null(obj.attr!=null),或者我希望变量始终不为null(在这种情况下,null表示代码中的其他地方存在错误)。如果我正在编写一个参数(字符串s)为null的方法(比如isUpperCase),我会显式测试null,然后抛出一个IllegalArgumentException


    我从来没有做过的,就是默默地从空值中恢复。如果一个方法应该返回字符串中的大写字符数,并且传递的参数为null,那么我永远不会通过静默返回0来“隐藏”它,从而掩盖潜在的错误。

    个人(使用C++),除非有一个强大的契约确保我的指针不是null ptr,否则我总是测试它们,并返回错误,如果允许的话,也可以静默返回。

    在Objective-C中,您可以安全地使用nil执行任何操作。您可以使用非nil执行任何操作,nil最终成为noop。事实证明,这非常方便。少了很多样板文件的空检查,并且为真正的异常情况保留了异常。或者这会被认为是草率的编码吗?

    永远不要捕捉
    NullReferenceException
    。这意味着你的代码有很大的问题。我不确定每个人都理解我问题的意图,但我将从中得出结论,它从来没有真正有用过,也没有使用它的模式。我知道为什么我们不应该这样做,因为有更好的方法来解决这个问题