java-捕获空指针异常是代码异味吗?
最近,我的一位同事编写了一些代码,以捕获整个方法周围的空指针异常,并返回单个结果。 我指出了空指针可能有多种原因,因此我们将其更改为对一个结果的防御性检查。
但是,捕获NullPointerException对我来说似乎是错误的。 在我看来,空指针异常是错误代码的结果,而不是系统中预期的异常。
在任何情况下捕获空指针异常都有意义吗?
18个解决方案
36 votes
是的,捕获任何RuntimeException几乎总是一种代码异味。 C2 Wiki似乎同意这一观点。
例外可能是一些特殊防御性的代码段,它们运行着来自其他模块的几乎随机的代码。 这种防御性结构的示例包括EDT,ThreadPools / Executors和插件系统。
Joachim Sauer answered 2019-10-12T21:25:40Z
23 votes
我可以想到曾经捕获2566542520226415615616的一种用途:
catch (NullPointerException) {
ApplyPainfulElectricShockToProgrammer();
}
Jeffrey L Whitledge answered 2019-10-12T21:26:04Z
15 votes
有时由于第三方库中的错误,我不得不捕获nullpointer异常。 我们使用的库引发了该异常,对此我们无能为力。
在这种情况下,可以捕获它,否则不能捕获。
Shervin Asgari answered 2019-10-12T21:26:34Z
7 votes
这取决于。
这个同事的经验如何? 他这样做是出于无知/懒惰,还是有充分的理由呢? (像这样的主线程在所有其他事物之上,并且永远都不会死吗?)
90%的时间捕获运行时异常是错误的,99%的NullPointerException捕获是错误的(如果原因是“我得到了很多……”那么整个程序员都是错误的,您应该注意 他正在执行的其余代码)
但是在某些情况下,捕获NullPointerException是可以接受的。
OscarRyz answered 2019-10-12T21:27:13Z
3 votes
总的来说,我认为这是一种代码气味。 在我看来,防守检查更好。 我将其扩展为涵盖大多数未经检查的异常,但事件循环等除外,这些异常希望捕获所有错误以进行报告/记录。
我能想到的异常是围绕对无法修改的库的调用,该库可能会响应某些断言失败而产生空指针异常,而这种断言失败很难主动检查。
Michael Ekstrand answered 2019-10-12T21:27:44Z
3 votes
滑稽
我刚刚发现一些不应在工作中完成的事情:
public static boolean isValidDate(final String stringDateValue) {
String exp = "^[0-9]{2}/[0-9]{2}/[0-9]{4}$";
boolean isValid = false;
try {
if (Pattern.matches(exp, stringDateValue)) {
String[] dateArray = stringDateValue.split("/");
if (dateArray.length == 3) {
GregorianCalendar gregorianCalendar = new GregorianCalendar();
int annee = new Integer(dateArray[2]).intValue();
int mois = new Integer(dateArray[1]).intValue();
int jour = new Integer(dateArray[0]).intValue();
gregorianCalendar = new GregorianCalendar(annee, mois - 1,
jour);
gregorianCalendar.setLenient(false);
gregorianCalendar.get(GregorianCalendar.YEAR);
gregorianCalendar.get(GregorianCalendar.MONTH);
gregorianCalendar.get(GregorianCalendar.DAY_OF_MONTH);
isValid = true;
}
}
} catch (Exception e) {
isValid = false;
}
return isValid;
}
baaad :)
开发人员希望日历引发此类异常:
java.lang.IllegalArgumentException: DAY_OF_MONTH
at java.util.GregorianCalendar.computeTime(GregorianCalendar.java:2316)
at java.util.Calendar.updateTime(Calendar.java:2260)
at java.util.Calendar.complete(Calendar.java:1305)
at java.util.Calendar.get(Calendar.java:1088)
使值无效...
是的,它可以工作,但不是很好的做法...
引发异常(尤其是填充堆栈跟踪)的成本比仅手动检查数据而没有异常要高得多。
Sebastien Lorber answered 2019-10-12T21:28:47Z
3 votes
不好,但是可以产生优化的字节码。
如果大多数时候Integer null不是not null,则检查会降低整体性能。 支票本身需要3条指令(0-4)。 然后,整个案例需要7条指令(0-14)。
public class IfNotNull {
public Integer i;
public String getIAsString() {
if (i != null) {
return i.toString();
} else {
return "";
}
}
}
public java.lang.String getIAsString();
Code:
0: aload_0
1: getfield #2 // Field i:Ljava/lang/Integer;
4: ifnull 15
7: aload_0
8: getfield #2 // Field i:Ljava/lang/Integer;
11: invokevirtual #3 // Method java/lang/Integer.toString:()Ljava/lang/String;
14: areturn //
15: ldc #4 // String
17: areturn
遵循EAFP方法,该方法在Python世界中很常见。 null的情况会很昂贵,但not null089的情况我们只需要4条指令(0-7)。
public class TryCatch {
public Integer i;
public String getIAsString() {
try {
return i.toString();
} catch (NullPointerException npe) {
return "";
}
}
}
public java.lang.String getIAsString();
Code:
0: aload_0
1: getfield #2 // Field i:Ljava/lang/Integer;
4: invokevirtual #3 // Method java/lang/Integer.toString:()Ljava/lang/String;
7: areturn //
8: astore_1
9: ldc #5 // String a
11: areturn
Exception table:
from to target type
0 7 8 Class java/lang/NullPointerException
谁知道,JIT编译器是否可以对此进行优化?
PJA answered 2019-10-12T21:29:31Z
2 votes
必然是。
在大多数情况下,变量开头不应为null。 许多新语言都内置了对非空引用类型的支持-即,保证永远不会为null的类型。
对于允许传入值为null的时间,您需要进行检查。 但是,绝对地,例外绝对是执行此操作的不好方法。
if语句可能需要执行三个指令,并且是局部检查(意味着,在需要保证的位置进行检查)。
另一方面,使用异常可能需要更多指令-系统尝试查找方法,失败,在异常表中查找适当的异常处理程序,然后跳转到该位置执行该处理程序,然后再次跳转。 此外,检查可能是非本地的。 如果您的代码是这样的:
try
return contacts.find("Mom").getEmail()
catch (NullPointerException e)
return null
您不知道NPE是投在'getEmail'还是'find'中。
以一种更加模糊的方式编写的非常非常常见的模式的技术上较差的解决方案? 它不是等级,但是肯定闻起来很不好:/
Tac-Tics answered 2019-10-12T21:30:35Z
2 votes
您应该捕获NullPointerException(或具体地说,是任何Throwable)的唯一位置是在某些顶级或系统边界处,以便您的程序不会完全崩溃并可以恢复。 例如,在web.xml中设置错误页面可提供全部保护,以便Web应用程序可以从异常中恢复并通知用户。
GreenieMeanie answered 2019-10-12T21:31:00Z
1 votes
捕获NULL指针异常确实取决于上下文...应该努力避免使用严格的绝对规则...应在上下文中应用规则-希望捕获此异常并将整个软件置于某种STABLE状态-不执行或几乎不执行任何操作 几乎没有。 所有这些编码规则都应该很好理解
此时,您将查看您应该执行的软件AUDIT TRACE ...,并发现此异常的来源。
永远不会出现NULL指针异常的想法必须是可验证的。 首先进行静态分析(如果引入了第三方代码/组件,则将更加困难),然后使用相关工具进行详尽的状态空间搜索。
X
Xofo answered 2019-10-12T21:31:40Z
1 votes
捕获NPE(实际上是任何RTE)对于彻底终止基于Swing-GUI的应用程序可能是必需的。
编辑:在这种情况下,通常是通过UncaughtExceptionHandler完成的。
Rhangaun answered 2019-10-12T21:32:11Z
1 votes
那这个呢:
try
{
foo.x = bar;
}
catch (NullPointerException e)
{
// do whatever needs to be done
}
作为foo可能为null时的微优化,但几乎从来没有?
这个想法是这样的:
显式NULL检查仅需一条机器指令
另一方面,可以通过让NULL访问发生,捕获SIGSEGV并引发NullPointerException来完成第二个版本中的NULL检查。 如果对象不为NULL,则此方法免费。
Demi answered 2019-10-12T21:32:57Z
1 votes
很久以前,我有一种用途。 当通过键在集合中请求对象而找不到该对象时,一个特别愚蠢的库将抛出NullPointerException。 除了通过键查找之外,没有其他方法可以查找对象是否存在。
一段时间后,我们启动了供应商并开始修改该库。 现在,库引发了一个更好的异常(我的更改),并具有检查功能(其他人的更改)。
当然,我总是会在try块中只得到一行。 再有,我本人会犯错误的代码。
Joshua answered 2019-10-12T21:33:35Z
0 votes
我试图保证接口提供的结果,但是如果某个库或某人的代码可以因此产生null,并且期望捕获该结果可能是可行的。 当然,一旦发现问题,您的工作将由您决定。 有时检查null是否没有任何意义,如果您发现它为空,则可以采用其他方法解决问题,虽然效果不佳,但可以完成工作。
我在说什么就是尽可能使用例外,这是一个非常好的语言功能。
Tore answered 2019-10-12T21:34:06Z
0 votes
如果您的方法调用了外部接口(或SOAP API),并且有可能返回的值可能为Null,则捕获NullPointerException可能会很有用。 除此之外,捕获这些异常没有太大的好处。
AV. answered 2019-10-12T21:34:31Z
0 votes
它实际上取决于接口定义。 非结构化NPE处理与捕获Exception或Throwable一样糟糕。
空值对于标识未初始化状态很有用,而不是使用空字符串或max_int或其他任何值。 有一次我经常使用null的地方是与回调对象无关的地方。
我真的很喜欢Guice提供的@Nullable注解。
[http://code.google.com/docreader/#p=google-guice&s=google-guice&t=UseNullable]
消除NullPointerExceptions 您的代码库,您必须受到纪律处分 关于空引用。 我们去过 通过遵循和成功做到这一点 执行一个简单的规则:
每个参数都不为空,除非 明确指定。 谷歌 收藏库和JSR-305具有 简单的API来获取null 控制。 Preconditions.checkNotNull 如果为空,则可用于快速失败 找到引用,并且@Nullable可以 用于注释参数 允许为空值。
Guice默认情况下禁止null。 它会 拒绝注入null,失败的原因是 ProvisionException代替。 如果为null 您的班级允许的,您可以 用注释字段或参数 @Nullable。 Guice认出任何 @Nullable注解,例如 edu.umd.cs.findbugs.annotations.Nullable 或javax.annotation.Nullable。
Stevko answered 2019-10-12T21:35:36Z
0 votes
是的,在Java中,需要检查NullPointerException。
当应用程序在需要对象的情况下尝试使用null时抛出。 这些包括:
调用空对象的实例方法。访问或修改空对象的字段。将null的长度视为数组。访问或修改null插槽,就好像它是一个数组一样。将null抛出,就好像它是一个Throwable值一样。
应用程序应抛出此类的实例,以指示对null对象的其他非法使用。
读取文本文件(即XML)时未使用正确的ASCII字符和记录格式验证其文本的其他语言,则为NullPointerException。
mpurinton answered 2019-10-12T21:36:27Z
0 votes
如果程序员是新手,那么他可能会习惯于捕获所有异常,这会阻止他获得最终输出。 代码审阅者不应该接受此要求。
捕获任何RuntimeException都是不好的。 但是,如果确实有必要,那么在代码中添加注释对于将来将使用该代码的程序员将非常有帮助。 如果您不能写出合理的评论来捕捉它们,那么您必须避免使用它们。 期。
dnsh answered 2019-10-12T21:36:58Z