22

如果您认为有可能获得空指针异常,您应该使用 if 语句来确保变量不为空,还是应该只捕获异常?

我看不出有什么区别,因为您可以将逻辑放在 if 语句或 catch 块中处理空指针,那么哪个是最佳实践?

4

10 回答 10

37

我想说总是使用逻辑来捕获异常,而不是尝试/捕获。

验证时应该使用 Try/Catch,但是会发生一些奇怪的事情并导致错误,因此您可以更优雅地处理它。

于 2013-06-27T05:37:59.733 回答
20

这里没有一个单一的答案就足够了,这取决于

让我们看几个场景,这样你就可以明白我的意思了。

场景:采用不接受的引用类型参数的方法null

您正在定义一个方法,它需要一个引用类型参数,比如一个流对象,并且您不想接受null作为合法的输入参数。

在这种情况下,我会说合同不是null有效的输入。如果某些代码确实使用null引用调用了该方法,则合同被破坏。

这是一个例外,更具体地说,它是一个ArgumentNullException

例子:

public void Write(Stream stream)
{
    if (stream == null)
        throw new ArgumentNullException("stream");
    ...

在这种情况下,我绝对不会让代码执行,直到它尝试取消引用流,而是以 NullReferenceException 崩溃,因为那时我在知道原因时失去了所有反应能力。

问:为什么我不能返回false而不是抛出异常?

A. 因为返回值很容易被忽略,您是否真的希望您的“Write”方法只是因为您在调用代码中出现问题、传递错误的流对象或无法写入的内容而默默地跳过写入?我不会!

场景:方法返回一个对象的引用,有时没有对象

在这种情况下,合同是null合法的结果。在我看来,null这是要避免的事情,因为很难确保你在任何地方都能正确处理,但有时这是最好的方法。

在这种情况下,我会确保绕过结果,以确保当引用返回if时我不会崩溃。null

概括

如果仔细观察上述两种情况,您会注意到一件事:

在这两种情况下,都取决于预期的内容,合同的内容。

如果合同说“不是null”,则抛出异常。不要退回到旧式 API 的返回方式,false因为不应该默默地忽略异常问题,并且在代码中乱扔if语句以确保每个方法调用都成功不会使代码可读。

如果合同上说“null完全有可能”,用if语句处理。

广告

为了更好地null解决问题,我还敦促您为您和您的团队获取ReSharper,但请注意,此答案可以应用于任何类型的异常和错误处理,同样的原则也适用。

附带的属性可以嵌入到您的项目中以标记这些案例,然后 ReSharper 将突出显示有问题的代码。

public void Write([NotNull] Stream stream)

[CanBeNull]
public SomeObject GetSomeObject()

要详细了解 ReSharper 使用的合同属性,请参阅

于 2013-06-27T06:35:24.893 回答
4

好。例外就是这样。例外。当发生不可预见的事情并且不应该成为正常程序流程的一部分时,它们会被抛出。

这就是这里发生的事情。您希望在未指定时指定参数。这是出乎意料的,因此您应该抛出自己的异常通知用户。如果您想获得奖励积分,您还可以包括为什么必须指定参数的原因(如果不明显)。

我写了一系列关于异常的帖子:http: //blog.gauffin.org/2013/04/what-is-exceptions/

于 2013-06-27T05:53:07.130 回答
3

从性能的角度来看,这真的取决于你在做什么。当没有抛出异常时,try/catch 块对性能的影响是最小的(如果你真的需要最后百分之几的性能,你可能应该用 C++ 重写那部分代码)。抛出异常确实会对字符串操作等更简单的操作产生重大影响;但是一旦你在循环中获得文件/数据库操作,它们就会慢得多,以至于它再次成为微不足道的惩罚。不过,跨越应用程序域将对几乎任何事情产生重大影响。

操作性能/秒:

Mode/operation               Empty   String      File   Database    Complex
No exception            17,748,206  267,300     2,461   877         239
Catch without exception 15,415,757  261,456     2,476   871         236
Throw                      103,456   68,952     2,236   864         236
Rethrow original            53,481   41,889     2,324   852         230
Throw across AppDomain       3,073    2,942       930   574         160

其他测试结果以及测试源可从 .NET 中异常的性能影响一文中获得

于 2013-06-27T12:51:56.573 回答
0

我宁愿建议你使用if-statement例外NullReference。对于其他异常,try-catch应该足够好了。

我建议 if 语句用于NullReference异常的原因是因为 C# 不会告诉哪个变量为空。如果该行有多个对象可能为空,您将失去跟踪。如果您正在使用if-statement,则可以使用更好的日志记录来帮助您获得足够的信息。

于 2013-06-27T05:43:03.503 回答
0

主要问题是让方法完全返回 Null 是否是个好主意,我个人对此没有任何问题,但是一旦您尝试访问从此方法返回的对象的修饰符并且您忘记检查是否它被分配这成为一个问题。

肯对此有一个很好的回答

如果您总是期望找到一个值,那么如果它丢失则抛出异常。异常意味着存在问题。

如果该值可能丢失或存在,并且两者都对应用程序逻辑有效,则返回 null。

请参阅有关问题的讨论:

如果您打算指示没有可用数据,则返回 null 通常是最好的主意。

空对象表示已返回数据,而返回 null 则明确表示未返回任何内容。

此外,如果您尝试访问对象中的成员,返回 null 将导致 null 异常,这对于突出显示有问题的代码很有用 - 尝试访问什么都没有的成员是没有意义的。访问空对象的成员不会失败,这意味着错误可能未被发现。

一些进一步的阅读:

于 2013-06-27T06:00:09.693 回答
0

对语句使用 try catch 不是一个好主意。因为当您使用 try catch 它们时,似乎如果出现一些错误,代码将不会启动应用程序。但是如果你确定会出现什么样的错误,你可以在那个时候点击错误。这不会产生任何未知的错误。例如。

string name = null;

在这里,我将使用 name 变量,我相信这会抛出 Null Refrance Error 。

try
{
Console.writeLine("Name ={0}",name);
}
catch (NullRefranceException nex)
{
//handle the error 
}
catch(Exception ex)
{
 // handle error to prevent application being crashed. 
}

虽然您可以处理此类错误并使代码更具可读性,但这不是一个好习惯。像。

if(name !=null)
    Console.writeLine("Name ={0}",name);
于 2013-06-27T06:01:39.003 回答
0

根据我的经验,使用if更好,但前提是您实际上期望一个空引用指针。如果没有任何代码或上下文,很难说一个选项何时比另一个更好。

还有一个优化问题 -try-catch块中的代码不会被优化

于 2013-06-27T08:36:50.563 回答
0

一般来说,try-catch 块非常棒,因为只要发生异常,它们就会中断(移动到 catch 语句)。If-else 块依赖于您预测错误何时发生。

此外,当遇到错误时,catch 块不会阻止您的代码停止。

于 2013-06-27T12:01:59.253 回答
-2

使用Try Catch总是比if else更好 这里异常有两种类型,即已处理未处理的异常即使您想在异常可以处理时处理某些功能...

处理的异常总是允许您在 Catch 块内编写一些实现,例如。警告消息,发生此类异常时要处理的新函数。

于 2013-06-27T09:05:13.120 回答