如果捕获空指针异常不是一个好习惯,那么捕获异常是否是一个好习惯?

19

我听说捕获 NullPointerException 是一种不好的做法,并且我认为这是有道理的。让 NullPointerException 向上层抛出可以检测到出现了问题。但是,我经常看到我的朋友直接捕获 Exception,这样他们就不需要担心上面代码中可能出现的所有不同类型的异常。这是一种好的实践吗?还有哪些异常最好不要被处理?此外,在我们确定异常源代码时处理 NullPointerException 也对我来说很有意义。那么什么时候应该处理异常,什么时候不应该处理?另外,哪些异常最好不要被处理?


4
我听说捕获NullPointerException是一种不好的做法,我认为这样做是有道理的。让NullPointerException传播到顶层将允许检测到出现问题的情况,并不是很清楚。难道你把“catching”和“swallowing”混淆了吗? - leonbloy
3
жҚ•иҺ·NullPointerException并еҜ№е…¶иҝӣиЎҢеӨ„зҗҶжҳҜжІЎжңүй—®йўҳзҡ„пјҢиҝҷеҗҢж ·йҖӮз”ЁдәҺд»»дҪ•ејӮеёёгҖӮйҖҡеёёзҡ„жғіжі•жҳҜжҚ•иҺ·еҸҜд»ҘеӨ„зҗҶзҡ„ејӮеёёпјҢиҖҢдёҚжҚ•иҺ·пјҲдј йҖ’пјүйӮЈдәӣж— жі•еӨ„зҗҶзҡ„ејӮеёёгҖӮеӣ жӯӨпјҢжҲ‘дёҚеҗҢж„ҸдҪ жүҖеҗ¬еҲ°зҡ„и§ӮзӮ№гҖӮ - Steve Kuo
6个回答

31
Pokemon异常处理很糟糕。特别是,如果它是一个空块并且你只是将它们吞噬。您有特定类型的异常,因为它们实际上在特定的环境中具有特定的含义(本质上它们告诉您出了什么问题)。因此,通过捕获“Exception”异常,您正在表示您不关心这些异常,并且您不关心发生了什么。这可能不是您想要的。
一般来说,在捕获异常时应遵循以下规则:
  • 在此级别处理异常是否有意义?如果是,则处理它。如果不是,则传播。
  • 结合第一个规则,“处理”也可以是捕获、封装和重新抛出。这是一种防止抽象泄漏的方法,使调用者不必知道底层实现。
  • 空的catch块并不意味着您已经处理了异常。那被称为“吞噬”,至少,您需要记录异常。有时,异常的发生实际上是您的代码逻辑流程的一部分,因此您可能希望执行一些特殊操作(但这是例外情况而不是规则。最好检查导致异常的情况而不是将其纳入您的代码逻辑流程中)。
您可以在代码中轻松检查空值,因此没有必要显式捕获空指针异常。让NullPointerException发生没有意义(也是不良实践)。即使您有一些抛出NullPointerException的代码,并且这是您无法控制和修复的代码,您也应该确定导致NullPointerException的输入参数并具体测试它们。
另一个不应该捕获的异常是IllegalArgumentException。这个异常意味着你传递了一个不合理的参数。而不是捕获此异常,您应该显式测试输入参数以确保它们是明智的,并且不能引起IllegalArgumentException

18
"Pokemon 异常处理" 是什么? - Steve Kuo
34
catch(Exception ex) { 用于当你想要捕获所有异常时。} - John Vint
5
"Pokemon异常处理":要抓住它们全部 :D - tk_

14

捕获NullPointerException被认为是不好的实践的“原因”不是因为当出现问题时应该让它冒泡!仅基于异常类型就说任何异常“最好不要处理”似乎是个坏主意。

NPE被认为是编程错误的结果。一个严格正确的程序不应该生成它。看到它被捕获是不好的,因为通常意味着代码抛出了它,程序员决定只是捕获并掩盖它,而不是首先修复导致它的破损代码!

例如,如果由于业务原因与内部存在漏洞并偶尔引发空指针的API耦合在一起,捕获它并进行某些操作/向用户提供更好的消息是完全合法的。仅因为有人说“捕获Null Pointer Exception很糟糕”,就让'null'影响UI是没有意义的!

捕获java.lang.Exception在特定情况下可能是合法的,但通常“我懒”不是其中之一。例如,如果您正在实现API并想确保从未发生过规范中没有定义的异常,您可能会捕获Exception并将其包装在一些已定义的应用程序异常中。


7

只有在捕获异常可以增加一些价值时,才应该这样做。否则,应将其传递给调用方。

NullPointerException通常是代码中的一个错误。在catch块中如何明智地修复它呢?

不关心异常并不是好的编程习惯。


4
通常情况下,你只应该在能够以有意义的方式处理异常时才捕获它。如果你无法处理异常,应该让它传递到顶层并终止进程。例如,你能以有意义的方式从空指针异常或I/O错误中恢复吗?我认为不行。
我的异常处理规则如下:
  • 通常情况下,不应该捕获异常,除非你能够以有意义的方式处理它们。
  • 在进程/机器边界处捕获异常,记录捕获的异常及任何可用上下文,并重新抛出异常。如果异常是自定义异常,则可以将其包装在已知/有用于被调用进程的异常类型中并抛出。
  • 也可以在低级别上捕获异常,在那里你拥有最多的运行时上下文,记录异常和相关上下文,然后重新抛出异常。
  • 在重新抛出异常时,请使用 throw ; 而不是 throw caughtException ;。前者的语法保留了原始堆栈跟踪;使用后者的语法会创建一个新的堆栈跟踪,从 throw caughtException ; 开始——你失去了所有的上下文和调用堆栈,直到捕获异常的点。
  • 如果愿意,也可以在高层次上捕获异常并优雅地终止进程,记录异常信息以帮助调试和纠正潜在问题。
不要将异常用作流程控制机制(如果可能)。异常应该是特殊的自然现象。相反,预防性地强制执行调用者方法的合约(前提条件)。
更多信息,请参见 Bertrand Meyers 的书 Object Oriented Software Construction, 2nd ed.

2
回复"When rethrowing":在Java中,你不能直接使用"throw;"语句,你必须使用"throw caughtException;"语句,而这样做时不会丢失堆栈跟踪信息。 - hjhill

1
捕获异常的主要规则是你必须知道为什么这样做。当程序员想进行通用错误处理并且不关心具体发生了什么时,会捕获异常类。在这种情况下,他可以决定回滚事务或进行一些清理操作。 如果您正在捕获特定的异常,请尝试应用相同的规则。如果您确切地知道为什么要这样做,那么就去做吧。但是,在出现NPE的情况下,有人想要做一些真正特别的事情的情况非常罕见。

0
如果您有一种优雅的方式来处理异常,那么捕获它是很有用的;如果没有,希望调用者有一种好的方式来处理它。

1
如果没有,最终异常可以被记录。 - Peter Lawrey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接