如果他不期望为空,是否应该检查为空?


113

上周,我们就在应用程序的服务层中处理null产生了激烈的争论。问题是在.NET上下文中,但在Java和许多其他技术中将是相同的。

问题是:无论什么情况,您是否应该始终检查null并使代码正常工作,还是当意外收到null时让异常冒出?

在我看来,一方面,在您不期望它的地方检查空值(即,没有用户界面来处理它)与编写带有空catch的try块相同。您只是隐藏一个错误。错误可能是代码中的某些内容已更改,并且null现在是预期值,或者存在其他错误,并且将错误的ID传递给该方法。

另一方面,检查空值通常是一个好习惯。此外,如果进行检查,则应用程序可能会继续运行,而只有一小部分功能无效。然后,客户可能会报告一个小错误(例如“无法删除评论”),而不是更严重的错误(例如“无法打开页面X”)。

您遵循哪种做法,您对这两种方法的论点是什么?

更新:

我想添加一些有关我们特殊情况的细节。我们正在从数据库中检索一些对象,并对它们进行了一些处理(比如,建立一个集合)。编写代码的开发人员并不预期该对象可以为null,因此他不包含任何检查,并且在加载页面时出现错误,并且整个页面都没有加载。

显然,在这种情况下,应该进行检查。然后,我们讨论了是否应该检查每个处理的对象(即使不会丢失),以及是否应该静默中止最终的处理。

假设的好处是该页面将继续工作。考虑一下Stack Exchange上不同组(用户,评论,问题)的搜索结果。该方法可以检查是否为空,并中止用户的处理(由于错误为空),但返回“评论”和“问题”部分。该页面将继续工作,只是缺少“用户”部分(这是一个错误)。我们应该尽早失败并中断整个页面,还是继续工作并等待有人注意到“用户”部分丢失了?


62
Fox Mulder原则:信不信。
扬尼斯,2012年

14
@YannisRizos:这个原则是一个很好的原则-太好了,Java和C#的创建者让语言运行时环境自动完成了这一工作。因此,通常无需在代码中到处使用这些语言进行显式检查以检查是否为
布朗


我同意tdammers的回答。我认为检查null只是错误的,因为您没有合理的方法来处理它。但是,在您的方案中,您可以处理失败的部分,例如验证用户(或获取评论或其他内容)以及出现“哦,没有发生错误”框。我个人将所有异常记录在我的应用程序中,并过滤掉某些异常,例如404和连接意外关闭

2
assert(foo != null, "foo is web control within the repeater, there's no reason to expect it to be null, etc, etc...");
zzzzBov 2012年

Answers:


105

问题不仅仅在于您是否应该检查null还是让运行时抛出异常。这是应对这种意外情况的方法。

那么,您的选择是:

  • 抛出一个通用异常(NullReferenceException),使其冒泡;如果您自己不进行null检查,这将自动发生。
  • 抛出一个自定义异常,从更高层次上描述问题;这可以通过抛出null检查或捕获a NullReferenceException并抛出更具体的异常来实现。
  • 通过替换一个合适的默认值进行恢复。

没有一般规则,哪个是最佳解决方案。我个人会说:

  • 如果错误条件是代码中严重错误的征兆,则最好是通用异常,也就是说,一开始绝对不允许null值到达那里。这样的异常可能会一直冒泡到您设置的任何错误日志中,以便有人得到通知并修复该错误。
  • 如果提供半有用的输出比正确性更重要,则默认值解决方案是很好的,例如,Web浏览器接受技术上不正确的HTML并尽最大努力呈现出合理的效果。
  • 否则,我将处理特定的异常并在适当的地方处理它。

1
对于最终用户@Stilgar没有区别。对于开发人员而言,像“数据库服务器无法访问”之类的特定异常更为直观,即“空指针除外”
k3b

32
尽早而艰难地失败意味着线下发生更细微错误,错误身份验证,损坏的数据持续存储,信息泄漏以及其他有趣事件的风险降低。
拉尔斯·维克伦德

1
@Stilgar:这里有两个问题:无人照管的行为和可维护性。虽然对于无人值守的行为,特定的异常与通用的异常之间几乎没有什么区别,但是对于可维护性,它可以使“哦,这就是为什么事情会崩溃”与数小时的调试两项区别。
tdammers,2012年

3
tdammers是完全正确的。“没有将对象引用设置为对象的实例”是我最常看到的最烦人的异常之一。我宁愿看到一个特定的异常,无论它是带有参数名称的ArgumentNullException还是自定义异常“用户TK421不存在任何发布记录”。
肖恩·蔡斯

1
@ k3b对于最终用户而言,“数据库服务器不可访问”也非常有帮助。至少,对于任何对常见问题有一些了解的最终用户-可能会帮助他发现电缆松动,路由器需要重新启动等,而不必为有bug的软件感到生气。
朱莉娅·海沃德

58

恕我直言,尝试处理您不期望的空值会导致代码过于复杂。如果您不希望为null,请抛出ArgumentNullException。当人们检查该值是否为null并尝试编写一些毫无意义的代码时,我感到非常沮丧。同样的情况也适用于SingleOrDefault在某人真正期望时使用(或什至更糟的是获得收藏),Single以及在许多其他情况下(当人们不知道该怎么做)人们清楚地陈述其逻辑的情况。


而不是ArgumentNullException,应该使用代码合同(除非它是不支持代码合同的2010年前的源代码)。
阿森尼·穆尔琴科(

我同意你的看法。如果不期望为null,则不应以奇怪的方式对其进行处理,而应仅进行报告。
Giorgio'5

9
如果我没看错这个问题,则将一个ArgumentNullException计数视为“处理”空值:将防止以后出现空引用异常。
KutuluMike,2012年

@MichaelEdenfield:根据给定的问题,我认为这不算是真正的处理(我们的目标是无论如何都不使您的代码正常工作)。老实说,我经常忘记编写适当的代码块,如果传递null则会抛出该代码块。但是,我认为抛出NullArgumentException是最佳实践,而我认为最糟糕的做法是编写无法处理null的代码,而不是抛出异常返回,例如,将另一个null作为方法结果(或空字符串,空集合或-1) ,或者如果返回类型为void等,则跳过方法执行)。
empi 2012年

2
@Giorgio ArgumentNullException非常清楚地说明了问题所在以及解决方法。C#不会倾向于使用“未定义”。如果您以未定义的方式调用某些内容,则您的调用方式没有任何意义。例外是表明这一点的正确方法。现在,有时我将使解析方法在int无法解析(例如)的情况下返回null 。但是,在这种情况下,无法解释的结果是合理的可能性而不是使用错误。另请参阅本文
Kyralessa

35

根据null我的经验进行检查的习惯来自以前的C或C ++开发人员,在这些语言中,如果不进行检查,则很有可能隐藏严重的错误NULL。如您所知,在Java或C#中,情况有所不同,使用未经检查的null ref null将导致异常,因此只要您在调用方不忽略该错误,该错误就不会被秘密隐藏。因此,在大多数情况下,显式检查null并没有多大意义,并且会使代码过于复杂。这就是为什么我认为空检查在那些语言中是个好习惯(至少,不是一般而言)。

当然,该规则也有例外,以下是我可以想到的那些例外:

  • 您需要一条更好的,易于理解的错误消息,告诉用户错误的空引用出现在程序的哪个部分。因此,您对null的测试只会引发不同的异常,并带有不同的错误文本。显然,这样不会掩盖任何错误。

  • 您想使程序“更早失败”。例如,您要检查构造函数参数的空值,否则该对象引用将仅存储在成员变量中,并在以后使用。

  • 您可以安全地处理null引用的情况,而没有后续错误的风险,也不会掩盖严重的错误。

  • 您希望在当前上下文中使用一种完全不同的错误信号(例如,返回错误代码)


3
“您想要一个更好的,易于理解的错误消息”-我认为这是做到这一点的最佳理由。“对象引用未设置为对象的实例”或“空引用异常”从没有像“产品未实例化”那样有用。
pdr 2012年

@pdr:检查的另一个原因是要确保始终检测到它。
乔治

13
也许是“前C开发人员”。仅当这些人自己正在恢复C开发人员时,才可以“以前的C ++开发人员”。作为一名现代C ++开发人员,我对使用裸指针或鲁re动态分配的代码非常怀疑。事实上,我会忍不住扭转的说法,并说,C ++并没有遭受了OP描述,因为它的变量没有这样的Java和C#有额外的特殊空岬财产的问题。
Kerrek SB 2012年

7
您的第一段只是故事的一半:是的,如果在C#中使用空引用,则将获得异常,而在C ++中,将获得未定义的行为。但是,在精心编写C#,你被卡住高于精心编写的C ++更可为空引用。
詹姆斯·麦克奈利斯

封装越好,这个答案就越适用。
Radarbob 2015年

15

使用断言来测试和指示代码的前提条件/后置条件和不变式。

它使理解代码期望以及期望处理什么变得容易得多。

IMO断言是合适的检查,因为它是:

  • 高效(通常不用于发布),
  • 简短的(通常是一行)和
  • 清除(违反了前提条件,这是编程错误)。

我认为自我记录代码很重要,因此进行检查很不错。防御性的,快速故障的编程使维护方式变得更容易,这通常是大多数时间所花费的时间。

更新资料

精心整理。给最终用户一个在错误下可以很好地运行的应用程序通常是很好的,即尽可能多地显示。健壮性好,因为天堂只知道在关键时刻会破裂。

但是,开发人员和测试人员必须尽快意识到错误,因此您可能希望使用带有钩子的日志记录框架,该钩子可以向用户显示存在问题的警报。该警报可能应该显示给所有用户,但可能会根据运行时环境进行不同的调整。


断言发布中不存在对我来说是一个很大的负面因素,发布是您想要添加信息的确切时间
jk。

1
好吧,如果需要的话,也可以使用在发布中处于活动状态的assert ^ h ^ h ^ h条件抛出函数。我经常自己动手。
Macke 2015年

7

早期失败,经常失败。null是您可以获得的最佳意外值之一,因为一旦尝试使用它,很快就会失败。其他意外值不太容易检测。由于null每当您尝试使用它时,它都会自动失败,因此我认为它不需要显式检查。


28
我希望你的意思是:早点失败,快速失败,不要经常...
empi 2012年

12
问题在于,如果没有显式检查,则null值有时可能会在导致异常之前传播很远,然后很难找出它的起源。
Michael Borgwardt'5

@MichaelBorgwardt这不是堆栈跟踪的目的吗?
R0MANARMY'5

6
@ R0MANARMY:当将null值保存到某个字段并且NullPointerException抛出得多以后,堆栈跟踪无济于事。
Michael Borgwardt'5

@ R0MANARMY,即使您能够信任堆栈跟踪中的行号(在许多情况下也不能),某些行包含多个可能为空的变量。
Ohad Schneider

6
  • 检查null应该是您的第二天性

  • 您的API将被其他人使用,他们的期望可能与您的期望不同

  • 全面的单元测试通常强调需要进行空引用检查

  • 检查null并不意味着条件语句。如果您担心空检查会使代码的可读性降低,那么您可能需要考虑.NET代码协定。

  • 考虑安装ReSharper(或类似工具)以搜索代码以查找缺少的空引用检查


使用代码协定作为前提条件只是条件条件语句的美化。
CVn

是的,我同意,但我也认为使用代码协定时代码看起来更干净,即提高了可读性。
CodeART 2012年

4

我将从语义的角度考虑这个问题,即问自己一个空指针或空引用自变量代表什么。

如果函数或方法foo()的参数x为T类型,则x可以是强制性的可选的

在C ++中,您可以将强制性参数传递为

  • 一个值,例如void foo(T x)
  • 一个引用,例如void foo(T&x)。

在这两种情况下,您都没有检查NULL指针的问题。所以,在很多情况下,你并不需要一个空指针检查所有强制参数。

如果要传递可选参数,则可以使用指针并使用NULL值指示未提供任何值:

void foo(T* x)

一种替代方法是使用类似

void foo(shared_ptr<T> x)

在这种情况下,您可能要检查代码中的指针,因为x是否包含值或根本不包含值对方法foo()有所不同。

第三种也是最后一种情况是将指针用作必需 参数。在这种情况下,使用x == NULL调用foo(x)是一个错误,您必须决定如何处理此错误(与越界索引或任何无效输入相同):

  1. 无需检查:是否有错误让它崩溃,并希望该错误足够早地出现(在测试过程中)。如果不是这样(如果您没有足够早地失败),则希望它不会出现在生产系统中,因为用户体验将是他们看到应用程序崩溃。
  2. 检查方法开头的所有参数,并报告无效的NULL参数,例如,从foo()引发异常,然后让其他方法处理它。最好的办法是向用户显示一个对话框,指出该应用程序遇到内部错误并将要关闭。

除了更好的失败方法(向用户提供更多信息)之外,第二种方法的优点是更可能发现错误:每次使用错误的参数调用方法时,程序都会失败方法1该错误仅在执行了取消引用指针的语句后才会出现(例如,如果输入了if语句的右分支)。因此,方法2提供了一种更强的“早期失败”形式。

在Java中,您有较少的选择,因为所有对象都是使用始终为null的引用传递的。同样,如果null表示可选参数的NONE值,则检查null(可能)将是实现逻辑的一部分。

如果null为无效输入,则您将出错,并且我将采用与C ++指针类似的考虑因素。由于在Java中您可以捕获空指针异常,因此,如果方法foo()取消引用所有执行路径中的所有输入参数(对于小型方法可能经常发生),则上述方法1等同于方法2。

总结

  • 在C ++和Java中,检查可选参数是否为null都是程序逻辑的一部分。
  • 在C ++中,我将始终检查强制性参数以确保抛出适当的异常,以便程序可以以健壮的方式对其进行处理。
  • 在Java(或C#)中,如果存在为了增强“早期失败”形式而不会抛出的执行路径,我将检查强制性参数

编辑

感谢Stilgar提供更多详细信息。

就您而言,方法的结果似乎为空。同样,我认为您应该先澄清(并修复)方法的语义,然后才能做出决定。

因此,您有方法m1()调用方法m2(),而m2()返回对某个对象的引用(在Java中)或指针(在C ++中)。

m2()的语义是什么?m2()是否应始终返回非空结果?如果是这种情况,则空结果是内部错误(在m2()中)。如果在m1()中检查返回值,则可以得到更可靠的错误处理。如果不这样做,迟早会有例外。也许不吧。希望在测试期间而不是部署之后引发异常。问题:如果m2()永远不要返回null,为什么它返回null?也许它应该引发异常?m2()可能是越野车。

另一种选择是,返回null是方法m2()的语义的一部分,即它具有可选的结果,该结果应记录在该方法的Javadoc文档中。在这种情况下,可以为空值。方法m1()应该将其检查为其他任何值:这里没有错误,但可能检查结果是否为null只是程序逻辑的一部分。


在没有情况的情况下,不是参数为空。我们进行了数据库调用,要求提供预期存在但实际上不存在的某些内容。问题是我们是否应该检查每个对象是否存在,或者仅在我们期望它丢失时才应该检查。
史迪加

因此,方法返回的结果是对对象的引用,而null是用于表示结果的值:NOT FOUND。我理解正确吗?
Giorgio'5

我已用其他详细信息更新了问题。
斯蒂尔加

3

我的一般方法是永远不要测试您不知道如何处理的错误情况。这样,在每个特定实例中需要回答的问题就变成了:在出现意外值的情况下,您可以做一些合理事情null吗?

如果可以通过替换另一个值(例如,空集合或默认值或实例)来安全地继续操作,则一定要这样做。@Shahbaz在《魔兽世界》中将一个图像替换为另一个图像的例子属于该类别。图像本身可能只是装饰,没有功能影响。(在调试版本中,我将使用尖叫的颜色来引起注意替换已发生的事实,但这在很大程度上取决于应用程序的性质。)但是,请记录有关该错误的详细信息,以便您知道该错误的发生。否则,您将隐藏您可能想知道的错误。对用户隐藏它是一回事(同样,假设处理可以安全地继续);向开发人员隐藏它是另一回事。

如果在存在null值的情况下不能安全继续,则失败并显示明智的错误;通常,当操作明显无法成功时,我宁愿尽快失败,这意味着检查前提条件。有时您不希望立即失败,而要尽可能长地推迟失败;例如,在与密码相关的应用程序中会出现这种情况,在这种应用程序中,旁通道攻击可能会泄露您不想要的信息。最后,让错误冒泡到某个通用错误处理程序,该错误处理程序随后记录相关的详细信息,并向用户显示一个不错的(无论多么不错)错误消息。

还值得注意的是,测试/ QA /调试版本与生产/发行版本之间的正确响应可能会非常不同。在调试版本中,我会尽力而为地尽早失败,并给出非常详细的错误消息,以使其完全清楚地表明存在问题,并允许事后确定确定需要解决的问题。当生产版本遇到安全可恢复的错误时,可能应该支持恢复。


当然,在链上有通用的错误处理程序。日志的问题在于很长一段时间可能没有人检查它们。
斯蒂尔加

@Stilgar,如果没有人可以检查日志,那么存在或不存在空值检查都不是问题。
CVn 2012年

2
有一个问题。如果存在仅将错误隐藏并写入日志的空检查,则最终用户可能不会注意到系统长时间无法正常运行。
史迪加

@Stilgar,这完全取决于错误的性质。就像我在帖子中所说的那样,只有您可以安全地继续操作,才应该替换/忽略意外的null。例如,在发行版本中使用一个映像而不是另一个映像(在调试版本中,尽早并尽可能地失败,以使问题变得明显)是与返回无效结果进行计算的野兽。(经过编辑的答案中包括了这一点。)
CVn

1
除非您能以某种方式记录并报告错误(而不必过于依赖精明的用户),否则我将尽早快速地甚至在生产中失败。隐藏用户部署的错误是一回事-将它们隐藏起来很危险。同样,允许用户忍受细微的错误可能会削弱他们对您的应用程序的信心。有时最好咬一下子弹,让他们知道有一个错误并且您要尽快解决。
Merlyn Morgan-Graham

2

当然NULL不是预期,但总有虫子!

我相信您应该检查您NULL是否不期望它。让我给您示例(尽管它们不是Java语言)。

  • 在《魔兽世界》中,由于存在一个错误,开发人员之一的形象出现在了许多对象的立方体上。想象一下,如果图形引擎不期望 NULL指针,那么将会发生崩溃,而对于用户而言,它却不是那么致命(甚至很有趣)。至少,您不会意外失去连接或任何保存点。

    这是一个检查NULL防止崩溃的示例,该案例已被静默处理。

  • 想象一下一个银行出纳员程序。该接口进行一些检查,并将输入数据发送到基础部分以执行汇款。如果核心部分预计不接收NULL,然后在界面中的错误可以在交易中间产生问题,可能还有一些钱迷路(或更糟的是,重复)。

    “问题”是指崩溃(如崩溃崩溃(例如,程序是用C ++编写的),而不是空指针异常)。在这种情况下,如果遇到NULL,则事务需要回滚(如果不对NULL进行变量检查,那当然是不可能的!)

我敢肯定你知道这个主意。

检查函数自变量的有效性不会使代码混乱,因为这是对函数顶部的几次检查(不散布在中间),并大大提高了健壮性。

如果必须在“程序告诉用户它已失败并正常关闭或回退到可能创建错误日志的一致状态”和“访问冲突”之间进行选择,您是否会选择第一个?这意味着每个功能都应该为有缺陷的代码调用做好准备,而不是仅仅因为错误总是存在而期望一切都正确。


您的第二个例子证明了您的观点。在银行交易中,如果出现任何问题,交易应中止。恰恰在您掩盖错误时,金钱才可能丢失或重复。检查是否为空就像“客户
汇出零钱

@Stilgar,相反!检查NULL将被消息中止。不检查NULL将导致崩溃。现在,崩溃在交易开始时可能还不错,但在交易中间可能会带来灾难性的后果。(我没有说银行转帐应该像游戏一样处理错误!只是应该处理错误)
Shahbaz 2012年

2
“事务”的全部要点是它不能完成一半:)如果有错误,则将其回滚。
斯蒂尔加

对于实际上需要事务语义的任何事情,这都是可怕的建议。您应该使所有事务都是原子性和幂等的,否则,您所犯的任何错误都将保证所丢失或重复的资源(金钱)。如果必须处理非原子或非幂等操作,则应非常小心地将其包装在保证原子和幂等行为的层中(即使您必须自己编写这些层)。总是想:如果在进行此交易时流星击中了Web服务器,会发生什么?
Merlyn Morgan-Graham

1
@ MerlynMorgan-Graham,我这样做了。希望能消除混乱。
沙巴兹(Shahbaz)2012年

2

如其他答案所指出的如果你没想到的话NULL,用投掷来弄清楚ArgumentNullException。我认为,在调试项目时,它可以帮助您更快地发现程序逻辑中的错误。

因此,您将要发布软件,如果您恢复了这些NullRefrences检查,就不会错过任何软件逻辑,这可以确保不会弹出严重的错误。

另一点是,如果NULL检查功能的参数,则可以决定该功能是否正确。如果不是,请找到对函数的所有引用,然后在将参数传递给函数之前检查可能导致空引用的情况。


1

null系统中的每一个都是一个等待被发现的滴答定时炸弹。null在代码与不受控制的代码进行交互的边界处进行检查,并禁止null在自己的代码内进行。这使您摆脱了问题,而不必天真地信任外来代码。使用异常或某种Maybe/ Nothing类型代替。


0

尽管最终会抛出一个空指针异常,但它通常会与您获得空指针的位置相距甚远。帮自己一个忙,并至少记录下您尽快混入空指针这一事实,并缩短修复错误的时间。

即使您现在不知道该怎么办,记录事件也会在以后节省您的时间。也许获得票证的人将能够利用节省的时间来找出正确的响应。


-1

由于Fail early, fail fast如@DeadMG(@empi)所述,由于Web应用程序必须能够在错误下正常运行,因此不可行,因此应执行规则

没有日志就不会捕获异常

因此,作为开发人员,您可以通过检查日志来了解潜在的问题。

如果您使用的是log4net或log4j之类的日志记录框架,则可以设置一个附加的特殊日志记录输出(aka附加程序),向您发送错误和致命错误消息。让您随时了解情况

[更新]

如果页面的最终用户不应该知道该错误,则可以设置一个追加程序,以向您发送错误消息和致命错误消息,并及时通知您。

如果页面的最终用户可以看到隐秘的错误消息,则可以设置一个附加程序,将页面处理的错误日志放在页面末尾。

无论您如何使用日志记录,如果吞下异常,程序都会继续处理有意义的数据,并且吞咽不再安静。


1
问题是页面发生了什么?
Stilgar

我们如何知道数据有意义并且系统处于一致状态。毕竟错误是意外的,所以我们不知道会带来什么影响。
斯蒂尔加

“自从早期失败以来,@ DeadMG(@empi)所述的快速失败是不可行的,因为Web应用程序必须在您应执行规则的错误下才能很好地工作”:人们总是可以捕获所有异常(捕获(可抛出t)),并且重定向到某些错误页面。这不可能吗?
乔治

-1

这个问题已经有了不错的答案,可能是它们的补充:我更喜欢代码中的断言。如果您的代码只能与有效对象一起使用,而螺母只能为null,则应声明null值。

在这种情况下的断言会使任何单元和/或集成测试失败,并显示准确的消息,因此您可以在生产之前非常迅速地确定问题。如果这样的错误通过了测试并进入生产阶段(应该取消激活断言),您将收到NpEx和一个严重的错误,但是比一些较小的错误要好得多,后者会更加模糊并在其他地方弹出代码,并且修复起来会更昂贵。

此外,如果有人必须使用您的代码断言,则还可以告诉他有关您在设计/编写代码期间所做的假设(在这种情况下:嘿,伙计,必须显示此对象!),这使维护更加容易。


你能写点什么赞成票吗?我希望进行讨论。Thanx
GeT 2012年

我没有投反对票,我同意你的一般想法。该语言需要一些工作。您的断言定义了API的合同,如果违反了这些合同,则您会提早失败/快速失败。在应用程序的皮肤上执行此操作将使您的代码用户知道他们在代码中做错了什么。如果他们看到堆栈在您的代码凹进处向下移动,他们可能会认为您的代码有错误-您也可能会这样认为,直到获得可靠的repro并对其进行调试为止。
Merlyn Morgan-Graham

-1

我通常检查是否存在null,但会抛出一个异常来“处理”意外的null,该异常给出了有关null发生位置的更多详细信息。

编辑:如果在不希望出现某些错误的情况下得到null,则程序应终止。


-1

这取决于异常的语言实现。异常使您可以采取一些措施,以防止损坏数据或在系统进入意外状态时干净地释放资源。这与错误处理不同,后者是可以预见的。我的理念是,应尽可能减少异常处理。是噪音 通过处理异常,您的方法可以做任何合理的事情吗?可以恢复吗?它可以修复或防止进一步的损坏吗?如果您只是要捕获异常,然后从方法中返回或以其他无害的方式失败,那么捕获异常确实没有意义。您只会增加方法的噪声和复杂性,并且可能在设计中隐藏了故障源。在这种情况下,我会让故障冒泡并被外部循环捕获。如果您可以执行某些操作,例如修复对象或将其标记为损坏,或者释放一些关键资源(例如锁定文件)或通过完全关闭套接字,则可以很好地使用异常。如果您实际上希望NULL作为有效的边缘情况频繁出现,那么您应该在常规逻辑流程中使用if-the-else或switch-case语句或其他任何方式来处理此问题,而不使用异常处理。例如,以某种形式禁用的字段可以设置为NULL,这与表示保留为空白的字段的空字符串不同。这是您必须使用良好判断力和常识的领域。我从未听说过在每种情况下如何处理此问题的良好经验法则。如果您可以执行某些操作,例如修复对象或将其标记为损坏,或者释放一些关键资源(例如锁定文件)或通过完全关闭套接字,则可以很好地使用异常。如果您实际上希望NULL作为有效的边缘情况频繁出现,那么您应该在常规逻辑流程中使用if-the-else或switch-case语句或其他任何方式来处理此问题,而不使用异常处理。例如,以某种形式禁用的字段可以设置为NULL,这与表示保留为空白的字段的空字符串不同。这是您必须使用良好判断力和常识的领域。我从未听说过在每种情况下如何处理此问题的良好经验法则。如果您可以执行某些操作,例如修复对象或将其标记为损坏,或者释放一些关键资源(例如锁定文件)或通过完全关闭套接字,则可以很好地使用异常。如果您实际上希望NULL作为有效的边缘情况频繁出现,那么您应该在常规逻辑流程中使用if-the-else或switch-case语句或其他任何方式来处理此问题,而不使用异常处理。例如,以某种形式禁用的字段可以设置为NULL,这与表示保留为空白的字段的空字符串不同。这是您必须使用良好判断力和常识的领域。我从未听说过在每种情况下如何处理此问题的良好经验法则。

Java在其异常处理实现中使用“检查的异常”失败,其中必须在方法的“ throws”子句中捕获或声明方法中使用的对象可能引发的所有可能的异常。这与C ++和Python相反,您可以根据需要选择处理异常。在Java中,如果您修改方法的主体以使其包含可能引发异常的调用,则您可能会选择添加显式处理以处理可能不关心的异常,从而给代码增加噪音和复杂性,或者您必须将该异常添加到您正在修改的方法的“ throws”子句中,这不仅会增加噪音和混乱,而且会更改方法的签名。然后,无论使用哪种方法来处理您的方法现在可能引发的新异常,或者必须将异常添加到这些方法的“ throws”子句中,从而触发代码更改的多米诺效应,您都必须转到修改代码。“捕获或指定需求”必须是Java最令人讨厌的方面之一。RuntimeExceptions的异常异常和针对此设计错误的官方Java合理化是la脚。

最后一段与回答您的问题无关。我只是讨厌Java。

-诺亚


这篇文章很难阅读(文字墙)。您介意将其编辑为更好的形状吗?
蚊蚋
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.