Java NullPointerException-如何在Java中有效处理空指针
Java NullPointerException是未经检查的异常,并且进行了扩展RuntimeException。NullPointerException不会强制我们使用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可能会出现在代码中的任何位置,但是我根据自己的经验准备了最常出现的地点清单。
- 在未初始化的对象上调用方法
- 方法中传递的参数是
null - 调用
toString()对象的方法是null - 在
if不检查null相等性的情况下比较块中的对象属性 - 对于像Spring这样的依赖注入的框架来说,配置不正确
synchronized在一个对象上使用null- 链接的语句,即单个语句中的多个方法调用
这不是详尽的清单。还有其他几个地方和原因。如果您还可以回忆起其他任何内容,请发表评论。它也会帮助其他人(初学者)。
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 codeif (data != null && 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) |
显然,第二个堆栈跟踪更有用,并且使调试容易。

浙公网安备 33010602011771号