Java NullPointerException-如何在Java中有效处理空指针

Java NullPointerException是未经检查的异常,并且进行了扩展RuntimeExceptionNullPointerException不会强制我们使用catch块来处理它。

1.为什么在代码中出现NullPointerException

NullPointerException是代码中您尝试访问/修改尚未初始化的对象的情况。从本质上讲,它意味着对象引用变量没有指向任何地方,并且不指向任何内容或为“ null ”。一个抛出空指针异常的示例Java程序。

package com.howtodoinjava.demo.npe;
 
public class SampleNPE
{
   public static void main(String[] args)
   {
      String s = null;
      System.out.println( s.toString() );   // 's' is un-initialized and is null
   }
}

2. Java NullPointerException通常发生的常见位置

好吧,由于各种原因NullPointerException可能会出现在代码中的任何位置,但是我根据自己的经验准备了最常出现的地点清单。

  1. 在未初始化的对象上调用方法
  2. 方法中传递的参数是 null
  3. 调用toString()对象的方法是null
  4. if不检查null相等性的情况下比较块中的对象属性
  5. 对于像Spring这样的依赖注入的框架来说,配置不正确
  6. synchronized在一个对象上使用null
  7. 链接的语句,即单个语句中的多个方法调用

这不是详尽的清单。还有其他几个地方和原因。如果您还可以回忆起其他任何内容,请发表评论。它也会帮助其他人(初学者)。

3.避免Java NullPointerException的最佳方法

3.1。三元运算符

如果不为null,则运算符将得出左侧的值,否则将评估右侧。它具有如下语法:

布尔表达式?value1:value2;

如果expression计算为true,则整个表达式将返回value1,否则返回value2。它更像if-else构造,但是更有效和更具表现力。为了防止NullPointerException(NPE),请像以下代码一样使用此运算符:

字符串str =(参数==空)“ NA”:参数;

3.2。使用Apache Commons StringUtils进行字符串操作

Apache commons lang是用于各种操作之王的几个实用程序类的集合。其中之一是StringUtils.java使用StringUtils.isNotEmpty()验证作为参数传递的字符串是否为空或空字符串。如果不为null或为空;然后进一步使用它。

其他类似的方法是StringUtils。IsEmpty()和StringUtils.equals()。他们在javadocs中声称,如果StringUtils.isNotBlank()抛出NPE,则API中存在错误。

if (StringUtils.isNotEmpty(obj.getvalue())){
    String s = obj.getvalue();
    ....
}

3.3。很早检查方法参数是否为空

您应该始终将输入验证置于方法的开头,以使其余代码不必处理输入错误的可能性。因此,如果有人传递空值,那么事情将在堆栈中早点破裂,而不是在较深的位置(根本问题很难识别)中破裂。

在大多数情况下,针对快速故障行为是一个不错的选择。

3.4。考虑原始而不是对象

当对象引用指向无内容时,将发生空问题。因此,尽可能多地使用原语始终是安全的,因为它们不会受到空引用的影响。所有原语都必须附加一些默认值,因此请当心。

3.5。仔细考虑链接方法调用

虽然链式语句很容易在代码中查看,但它们不是NPE友好的。一条分散在多行中的语句将为您提供堆栈跟踪中第一行的行号,无论它出现在何处。

  ref.method1().method2().method3().methods4();

这种链式语句将仅打印“ 行号xyz中发生了NullPointerException”。调试这样的代码确实很难。避免此类呼叫。

3.6。使用String.valueOf()而不是toString()

如果必须打印任何对象的字符串表示形式,请不要使用object.toString()。这是NPE的非常软的目标。而是使用String.valueOf(object)。
即使object在第二种方法中为null,它也不会给出异常,并且将输出null来输出流。

3.7。避免从方法中返回null

避免NPE的一个很棒的技巧是返回空字符串或空集合,而不是返回null。在您的应用程序中一致地执行此操作。您会注意到,如果这样做,则不需要进行大量的空检查。

例如:

List<string> data = null;
 
@SuppressWarnings("unchecked")
public List getDataDemo()
{
   if(data == null)
      return Collections.EMPTY_LIST; //Returns unmodifiable list
   return data;
}

使用上述方法的用户即使错过了空检查,也不会看到难看的NPE。

3.8。不鼓励传递空参数

我已经看到一些方法声明,其中方法需要两个或多个参数。如果参数之一作为null传递,则方法以某种不同的方式起作用。避免这种情况。

相反,您应该定义两种方法;一个带有单个参数,第二个带有两个参数。强制传递参数。当您在方法内部编写应用程序逻辑时,这很有帮助,因为您可以确保方法参数不会为null。因此,您不会放置不必要的假设和断言。

3.9。在“安全”非空字符串上调用String.equals(String)

代替在下面的代码中编写字符串比较

public class SampleNPE {
   public void demoEqualData(String param) {
      if (param.equals("check me")) {
         // some code
      }
   }
}

像这样写上面的代码。即使参数作为null传递,这也不会在NPE中引起。

public class SampleNPE {
   public void demoEqualData(String param) {
      if ("check me".equals(param)) // Do like this
      {
         // some code
      }
   }
}

4.可用的NullPointerException安全操作

4.1。运算符实例

instanceof运算符是NPE安全的。因此,instanceof null总是返回false。它不会导致NullPointerException。如果您记住这一事实,则可以消除混乱的条件代码。

// Unnecessary code
if (data != null &amp;&amp; data instanceof InterestingData) {
}
 
// Less code. Better!!
if (data instanceof InterestingData) {
}

4.2。访问类的静态成员

如果您要处理静态变量或静态方法,则即使您的引用变量指向null,也不会得到null指针异常,因为静态变量和方法调用是在编译时根据类名绑定的,并且与对象无关

MyObject obj = null;
String attrib = obj.staticAttribute; //no NullPointerException because staticAttribute is static variable defined in class MyObject

5.如果必须在某些地方允许NullPointerException怎么办

Joshua bloch在有效的Java中说:“可以说,所有错误的方法调用都可以归结为非法论点或非法状态,但是其他例外通常用于某些种类的非法论据和状态。如果调用者在某个参数中传递了null,而该参数禁止使用null值,则约定NullPointerException将抛出而不是IllegalArgumentException

因此,如果必须NullPointerException在代码的某些地方允许使用,则请确保使它们比通常具有更多的信息性看下面的例子:

package com.howtodoinjava.demo.npe;
 
public class SampleNPE {
   public static void main(String[] args) {
      // call one method at a time
      doSomething(null);
      doSomethingElse(null);
   }
 
   private static String doSomething(final String param) {
      System.out.println(param.toString());
      return "I am done !!";
   }
 
   private static String doSomethingElse(final String param) {
      if (param == null) {
         throw new NullPointerException(
               " :: Parameter 'param' was null inside method 'doSomething'.");
      }
      System.out.println(param.toString());
      return "I am done !!";
   }
}

这两个方法调用的输出是这样的:

Exception in thread "main" java.lang.NullPointerException
 at com.howtodoinjava.demo.npe.SampleNPE.doSomething(SampleNPE.java:14)
 at com.howtodoinjava.demo.npe.SampleNPE.main(SampleNPE.java:8)
 
Exception in thread "main" java.lang.NullPointerException:  :: Parameter 'param' was null inside method 'doSomething'.
 at com.howtodoinjava.demo.npe.SampleNPE.doSomethingElse(SampleNPE.java:21)
 at com.howtodoinjava.demo.npe.SampleNPE.main(SampleNPE.java:8)

显然,第二个堆栈跟踪更有用,并且使调试容易。

原文地址:https://www.cnblogs.com/wangquanyi/p/11770979.html