zoukankan      html  css  js  c++  java
  • 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)

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

  • 相关阅读:
    nodejs MYSQL数据库执行多表查询
    【BZOJ3994】[SDOI2015]约数个数和 莫比乌斯反演
    【BZOJ2693】jzptab 莫比乌斯反演
    【BZOJ2154】Crash的数字表格 莫比乌斯反演
    【BZOJ2242】[SDOI2011]计算器 BSGS
    【BZOJ2005】[Noi2010]能量采集 欧拉函数
    【BZOJ1408】[Noi2002]Robot DP+数学
    【BZOJ2045】双亲数 莫比乌斯反演
    【BZOJ2186】[Sdoi2008]沙拉公主的困惑 线性筛素数
    【BZOJ4176】Lucas的数论 莫比乌斯反演
  • 原文地址:https://www.cnblogs.com/wangquanyi/p/11770979.html
Copyright © 2011-2022 走看看