捕捉和抛出nullpointerexception的最佳做法?

时间:2011-01-17 16:35:08

标签: java nullpointerexception

似乎抓住nullpointerexception不是一个好主意。如果是这样的话,为什么它会被方法抛出?应该只是被Exception捕获吗?

另外,如果我遇到一个null的参数(可以是像string这样的基本类型或带字段的类),我应该如何处理呢? (假设没有扔npe)?

由于

7 个答案:

答案 0 :(得分:14)

这是一个运行时异常,因此无意深入到您的程序代码中,只有 [更新] 在(或接近)顶级或JVM的 [/ update] 。由于运行时异常发出严重问题(通常是严重的编程错误,配置/集成问题等),因此最好让它们传播到顶部,这通常会使整个线程失败。这给出了一个强烈的信号,即出现问题并需要尽快修复。

另见Is Catching a Null Pointer Exception a Code Smell?

  

另外,如果我遇到一个null [...]的参数,我应该如何处理呢?

一般来说,扔NPE是可以的。但是,根据具体情况,您还可以考虑IllegalArgumentExceptionusing an assertion。另见

答案 1 :(得分:6)

nullpointerexception通常表示programmer error。如果你不期望这样的程序员错误,你将不会捕获空指针异常。例如,假设您使用一个P类型的参数实现了一个方法myMethod。

void myMethod(P x)

假设您不希望参数x为null。在这种情况下,您可能不会检查null。为什么?因为您假设正在使用您的方法的程序员将正确使用它并且不会传递null。在这种情况下,我不是说你应该或不应该检查是否为null。我只是想回答为什么有时一个方法抛出空指针异常并且不应该被捕获。原因如下:您的方法可能抛出空指针异常,因为有人没有正确使用它(传递null)。使用您的方法的程序员可能知道如果方法使用错误,它可能会抛出nullpointerexcetption。但即使他使用您的方法错误,也不会捕获异常,因为每个人都认为该方法没有被滥用。

你的第二个问题:首先,String是一个Object,而不是一个原始类型。其次,原语不能为空(原语是整数,双精度,浮点数,字符,布尔值和其他一些)。现在,如果您遇到一个null参数且它不应该为null(换句话说,您收到了非法参数),您有一些选择:

  • 抛出IllegalArgumentException,表示参数为null,您的方法期望它不为空。
  • 什么都不做。假设您的方法正确使用(换句话说,假设没有程序员错误)。
  • 使用assertionsassert(x != null);

我个人不是defensive programming的粉丝,通常更喜欢第二种选择。但是,如果我想确保我的变量有一些不变量,我正在使用断言。但这些只是我的习惯而其他人可能不同意。

答案 2 :(得分:4)

这个答案可能很长,但我认为值得。

  

似乎抓住nullpointerexception不是一个好主意。

你是对的,你不应该捕获NullPointerException,也不应该捕获任何运行时异常。

  

如果是这样的话,为什么它会被方法抛出?它应该被异常捕获吗?

用于表示发现了编程错误。这些编程错误可以而且应该用代码修复(也就是说,它们是可以预防的)

  

另外,如果我遇到一个null参数,我应该怎么处理呢? [...](假设没有扔npe)?

这取决于你想用它做什么。对于某些逻辑,可以允许null值。如果是这种情况,则验证是否存在null并对其执行某些操作,要么提供默认值,要么避免将messaged发送到null。

例如。假设您有一个结算信息系统,并且您拥有保存客户信息的代码,您可以选择保存客户的额外信息。

在这种情况下,可选消息可能为null,您的代码应验证其存在。

例如:

/**
* ...
* @param - OptionalMessage may be null, include anything else you wan to save.
*/
public void sendCustomerInformation( Customer c , OptionalMessage optionalMessage ) { 
   SomeMessage message = SomeMessage.createMessage();
   message.setHeader( c.name() );
   message.setCustomerInformation( c );
   if( optionalMessage != null ) { // is optional? handle it
      message.add( optionalMessage.status() );
      message.add( optionalMessage.summary() );
      message.add( optionalMessage.message() );
    }
 }

}

验证是否存在null并记录它。

但是同样的代码也有一个客户作为参数,在这种情况下你可以:

a)什么都不做 b)也验证它 c)根据此级别的抽象级别抛出不同的异常。

例如,上面的代码, a)没有。这将导致NullPointerException,其中调用代码c.name(),并且应该在开发测试的早期捕获它。此外,它应该记录在javadoc的param和throws中。

/**
 * ...
 * @param  c - The customer whose information is to be sent. NotNull 
 * ...
 * @throws NullPointerException if the customer is null
 */
public void sendCustomerInformation( Customer c , OptionalMessage optionalMessage ) { 
   SomeMessage message = SomeMessage.createMessage();
   ...

如果有人用null调用此方法,Npe将指示他们编写了错误的代码。另外,Npe会很快说出编码错误的原因和位置(当使用null客户调用sendCustomerInformation时。

选项 b)验证它。可能是这种情况,当你可能允许处理一个空客户时(它没有意义,但它是一个选项)

在这种情况下,您可以对其进行验证并提前返回(以我已完成方式)

public void sendCustomerInformation( Customer c , OptionalMessage optionalMessage ) { 
   if( cusomer == null ) {  return; // I'm done! } 
   // else 
   SomeMessage message = ... 
   ..
}

或者可以创建替代品:

public void sendCustomerInformation( Customer c , OptionalMessage optionalMessage ) { 
   if( cusomer == null ) {  c = new EmptyCustomer() ;} 
   // else 
   SomeMessage message = ... 
   ..
}

选项 c)这类似于a,但是,在这种情况下,您根据抽象级别抛出异常。例如,如果要在GUI或其他东西中向最终用户显示,那么抛出Npe可能没有意义:

public void sendCustomerInformation( Customer c , OptionalMessage optionalMessage ) { 
   if( cusomer == null ) {  
     // oh oh  something went wrong. 
     log.fatal("Invalid argument on \"sendCustomerInformation\" );
     throw new MyApplicationException("Dear customer, the information yada yaa"); 
   } 
   ...

如果这是app中的某种invalida状态:

public void sendCustomerInformation( Customer c , OptionalMessage optionalMessage ) { 
   if( cusomer == null ) {  
     // wait a minute, how could... why did.. what?
     throw new IllegalStateException("Hey, I got null on sendCustomerInformation and this shouldn't happen");
   }
   ...

因为app可能负责将该对象/参数保持在有效的形状中。

<强>结论

所以它取决于场景,但总的来说,NullPointerException(以及大多数RuntimeExceptions)表示可以用代码修复的东西(这是程序员的错误),你可以随时做些什么。在某些情况下,你无法做些什么,你可以做的最好的事情就是让它弹出来。

我希望这会有所帮助。

另请参阅:Exception other than RuntimeException

答案 3 :(得分:2)

如果有人非法将Null传递给您的方法,则抛出IllegalArgumentException而不是NP。这更好地描述了错误。

答案 4 :(得分:1)

NPERuntimeException S IN时一般有一个编码错误大多抛出,这就是为什么抓住他们不被认为是一个好主意。应该做的是修复无法处理空输入的代码。

问题的第二部分是什么,应该如何处理空输入。这完全取决于您在代码中合理期望的内容。

让我们说,你从一个数据库表中读取数据,并从一个空的列读取一个空值,这绝对不是一个特例,所以你的代码应该把它处理从商业的角度来看其appropiate(如忽略整个行,提示用户输入值或只使用虚拟值。)

不过,如果你从一个非空列读取空值,比如主键,你应该抛出一个应用程序特定的例外,这是(希望)通过应用程序的UI处理。

因此,答案是真的就这么简单:如果空是可以正常操作过程中发生的,相应的处理,如果不是一个值,抛出一个检查业务异常,而不是NPE

答案 5 :(得分:1)

您可能希望捕获 NPE的最可能情况是,当您实现某种框架时,即您不想终止您的应用程序,但报告错误,你有办法(明智地)继续你的申请。

答案 6 :(得分:0)

为了避免代码中的空值检查,在大多数情况下,返回空对象或空列表/ map / set而不是null是合适的。