try Catch或If语句?

Try Catch or If statement?

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

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


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

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


这里没有一个能满足的答案,这要看情况而定。

让我们来看看我的意思。

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

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

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

这是一个异常,更具体地说,它是一个argumentNullException。

例子:

1
2
3
4
5
public void Write(Stream stream)
{
    if (stream == null)
        throw new ArgumentNullException("stream");
    ...

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

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

A.由于返回值很容易被静默忽略,您真的希望您的"写入"方法只是静默地跳过写入操作,因为您在调用代码中出错,传递了错误的流对象或无法写入的内容?我不会!

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

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

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

泛化

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

在这两种情况下,归根结底是什么是预期的,什么是合同。

如果合同上说"不是null",就抛出一个例外。不要回到老式的API返回false的方式,因为一个异常的问题不应该被静默地忽略,并且在代码中乱放if语句以确保每一个方法调用成功不会使代码可读。

如果合同上说"null是完全可能的",就用if声明来处理。

广告

为了更好地掌握null问题,我也希望您能为您和您的团队重新分析,但是请注意,这个答案可以应用于任何类型的异常和错误处理,同样的原则也适用。

有了它,您可以将属性嵌入到项目中来标记这些情况,然后resharper将突出显示有问题的代码。

1
2
3
4
public void Write([NotNull] Stream stream)

[CanBeNull]
public SomeObject GetSomeObject()

要了解有关Resharper使用的合同属性的更多信息,请参见

  • Resharper NullReferenceException分析及其契约
  • Resharper 7中的合同注释


好。例外就是这样。例外情况。它们在发生了不可预见的事情时抛出,不应成为正常程序流的一部分。

这就是这里发生的事情。如果参数不是,则应指定该参数。这是出乎意料的,因此您应该抛出自己的异常来通知用户这一点。如果你想得到加分,你也可以包括为什么必须指定参数的原因(如果不明显的话)。

我写了一系列关于例外的文章:http://blog.gauffin.org/2013/04/what-is-exceptions/


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

每秒操作性能:

1
2
3
4
5
6
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中异常的性能影响文章中获得。


一般来说,Try-Catch块很好,因为每当发生异常时,它们都会中断(移动到catch语句)。如果其他块依赖于您预测错误何时发生。

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


在我的经验中,使用if更好,但前提是实际需要一个空引用指针。如果没有任何代码或上下文,很难判断一个选项何时优于另一个选项。

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


对语句使用try catch不是一个好主意。因为当使用Try-Catch时,如果出现错误,代码似乎不会使应用程序死机。但是,如果你确定会出现什么样的错误,你可以点击那个错误。不会产生任何未知错误。例如.

1
string name = null;

这里我将使用name变量,我确信这将引发空折射错误。

1
2
3
4
5
6
7
8
9
10
11
12
try
{
Console.writeLine("Name ={0}",name);
}
catch (NullRefranceException nex)
{
//handle the error
}
catch(Exception ex)
{
 // handle error to prevent application being crashed.
}

这不是一个很好的实践,尽管您可以处理此类错误并使代码更可读。喜欢。

1
2
if(name !=null)
    Console.writeLine("Name ={0}",name);

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

肯对此有一个很好的答案:

If you are always expecting to find a value then throw the exception
if it is missing. The exception would mean that there was a problem.

If the value can be missing or present and both are valid for the
application logic then return a null.

关于这个问题,请看下面的讨论:

Returning null is usually the best idea if you intend to indicate that
no data is available.

An empty object implies data has been returned, whereas returning null
clearly indicates that nothing has been returned.

Additionally, returning a null will result in a null exception if you
attempt to access members in the object, which can be useful for
highlighting buggy code - attempting to access a member of nothing
makes no sense. Accessing members of an empty object will not fail
meaning bugs can go undiscovered.

进一步阅读:

  • 方法范围之外没有空值

  • 我们应该从方法中返回空值吗?


我建议您使用if-statement作为NullReference例外。对于其他例外情况,try-catch应该足够好。

我建议使用if语句来处理NullReference异常的原因是因为c不知道哪个变量是空的。如果该行有多个对象,则可能为空,您将丢失跟踪。如果您使用的是if-statement,那么您可以有更好的日志记录来帮助您获得足够的信息。


使用"尝试捕获"总是比使用"尝试捕获"要好。这里的异常有两种类型,即已处理异常和未处理异常即使你想在你能处理异常的时候处理一些函数…

处理的异常始终允许您在catch块中写入一些实现一条警告信息,当这种异常发生时要处理的新函数。