开发者社区> 程序员鸭哥> 正文

java.lang.NullPointerException

简介: java.lang.NullPointerException
+关注继续查看

之前一篇文章聊过异常排名《Java异常排行榜:哪个异常最常见?》,里面谈到国外一个网站对 Java 异常进行数据分析并排名,结果是 NullPointerException 排第一,本文正好对空指针异常做一个总结,希望对各位同学有所帮助。

在本文中,我展示了一个关于如何处理空指针异常的综合示例。在Java中,null 作为一个特殊值被对象引用,用来表示该对象当前指向的是一块未知内存数据。然而NullPointerException这个异常,则是程序在使用或访问一个对象的引用时,而该对象等于null则被抛出。

那些情况会引发该异常呢?

  • 被调用方法的对象为null。
  • 访问或修改一个null对象的字段。
  • 求一个数组为null对象的长度。
  • 访问或修改一个数组为null对象中的某一个值。
  • 被抛出的值是null并且是一个Throwable的子类。
  • 当你用null对象进行synchronized代码块。

NullPointerException 是 RuntimeException 的子类,因此,Javac 编译器并不会强迫你使用 try-catch 代码块来捕获该异常。


一、为什么需要 null ?


如上所述,null 是 Java 的一个特殊值。它在设计模式方面编码的过程中非常有用,例如空对象模式和单例模式。空对象模式提供了一个对象作为缺少给定类型对象的代理。而单例模式可以确保只创建一个类的实例,主要用于提供一个全局访问的对象。

例如,创建单例类的示例方法是将其所有构造函数声明为private,然后创建一个返回该类的唯一实例的公共方法,如下:

image

在这个例子中,我们声明了一个 Singleton 类的静态实例。该实例在 getInstance 方法内最多初始化一次。注意本例使用了 null 来确保创建的是唯一实例。


二、如何避免空指针异常


为了避免这种情况 NullPointerException ,请确保在使用运行程序之前,所有对象都已正确初始化。注意,当你声明一个引用变量时,即创建了一个指向对象的指针。在向对象请求方法或字段之前,您必须验证变量指针是否为空。

另外,如果引发异常,请使用堆栈中的异常信息进行跟踪。堆栈跟踪是由JVM提供,便于应用程序的调试。找到发生异常的方法和代码行,然后确定哪个引用为null。

在本文的余下部分,我们将介绍一些避免空指针异常的方法。但是,这些方法并非一劳永逸,因此,同学们在编写应用程序时应格外小心。

1、String变量与文本值比较

在编码过程中,String变量与文本值之间的比较是特别常见的。一般被比较的值可以是一个字符串或枚举值。因此,我们不要从空对象调用方法进行比较,而应考虑从文字值中调用方法。如下:

image.png

上面的代码片段则会抛出一个NullPointerException。但是,如果我们从文字中调用方法,那么执行流程通常会继续:

image.png

为什么呢?去看一下 JDK 源码 java.lang.String 便明白了。

image.png

2、检查方法的参数

在执行你自己的方法的主体之前,一定要检查方法传入的参数是否为空。只有在正确检查了参数后,才能继续执行该方法的相应逻辑。否则,您可以抛出一个 IllegalArgumentException 来通知调用方法所传递的参数有问题。

例如:

image.png

3、优先使用String.valueOf() 代替toString()

当您代码中的某个对象需要用字符串的方式来表示时,请避免使用该对象的toString方法;因为若你的对象引用为null,则会抛出 NullPointerException。

相反,考虑使用静态String.valueOf方法,该方法不会抛出任何异常,若对象引用为空,则打印「null」字符串。

有的同学可能会问为什么呢?还是那句话读源码 ^_^

下面是基类 Object 的 toString() 方法:

image.png

接着,咱们再来看看 String 的 valueOf() 方法做了什么呢?

image.png

4、使用三元运算符

该操作是非常有用的,可以帮助我们避免了NullPointerException。格式如下:

image.png

上面通过布尔表达式来判断。如果表达式结果为true,则返回value1,否则返回value2。我们可以使用三元运算符来处理空指针,如下所示:

image.png

如果str的引用为空,则消息变量将为空。否则,如果str指向实际数据,则该消息将保留它的前10个字符。

这里,一直有个疑惑困扰着我,为什么 Kotlin 这门语言去掉了三元运算符呢?知道的同学欢迎留言,一起来探讨~~~

5、创建返回空集合而不是null值的方法

一个非常好的操作是创建返回一个空集合的方法,而不是一个null值。因为你的代码可以遍历空集合并使用它的方法和字段,而不会抛出一个NullPointerException 。例如:

image.png

注意:要熟悉 Collections 这个集合工具类,里面有太多好用的方法了。

6、使用Apache的StringUtils类

Apache的Commons Lang是一个为 java.lang API 提供帮助工具的库,比如字符串操作方法。提供字符串操作的示例类是 StringUtils.java,它对输入的字符串进行了 null 判断。

你可以使用 StringUtils.isNotEmpty,  StringUtils.IsEmpty 和 StringUtils.equals 等方法,来避免NullPointerException。例如:

image.png

还是老规矩,咱们来读一下相应的源码。

image.png

7、习惯用 contains(), containsKey(), containsValue() 方法

如果您的程序在使用集合,请考虑使用contains,containsKey和containsValue方法。例如,从集合中找一个特定键的值:

image.png

在上面的代码片段中,我们未检查key是否真的存在于内部Map,因此返回的值可以是 null 。最安全的方法如下:

image.png

8、请检查使用的外部方法的返回值是否为 null

在编码中使用外部库是很常见的,这些库可能包含返回引用的方法,需确保返回的值不为 null 。另外,我们要养成在开发的过程中,养成阅读 Javadoc 的习惯,以便更好地理解其功能和返回值。

9、使用断言

断言在测试代码时非常有用,并且可以被使用,以避免 NullPointerException 。Java 断言是用 assert 关键字实现的,并抛出一个 AssertionError 。

请注意,您必须显式启用 JVM 的断言标志,一般在程序启动时,使用 –ea 参数来启用断言。否则,断言将被完全忽略。

使用 Java 断言的示例如下:

image.png

如果您执行上面的代码段并传递一个空参数getLength,则会出现以下错误消息:

image.png

最后,您可以使用测试框架  JUnit 提供的类 Assert 来使用断言。

10、单元测试

在测试代码的功能和正确性时,单元测试一般非常有用。因此,建议多花一些时间编写一些测试用例,来避免程序出现 NullPointerException。目前,我司的代码覆盖率要达到 95% 以上才能通过。


三、拥有 NullPointerException 的安全方法


1、访问类的静态成员或方法

当你的代码试图访问静态变量或类的方法时,即使对象的引用等于 null,JVM 也不会抛出一个 NullPointerException 。这是由于Java编译器在编译过程中将静态方法和字段存储在方法区或者常量池。因此,静态字段和方法不与对象相关联,而与类的名称相关联。

例如,下面的代码不会抛出NullPointerException:

image.png

注意,尽管 SampleClass 等于的实例 null 将会被正确执行。但是,对于静态方法或字段,最好以静态方式访问它们,比如SampleClass.printMessage()。

2、instanceof 操作符

instanceof 即使对象的引用等于 null,也可以使用该运算符。在 instanceof 操作时,参考值等于为null,不抛出 NullPointerException,而是返回 false 。例如,下面的代码片段:

image.png

正如预期的那样,执行的结果是:

image.png


四、参考


https://github.com/apache/commons-lang

https://github.com/junit-team/junit4

https://examples.javacodegeeks.com/java-basics/exceptions/java-lang-nullpointerexception-how-to-handle-null-pointer-exception

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
23639 0
阿里云服务器ECS远程登录用户名密码查询方法
阿里云服务器ECS远程连接登录输入用户名和密码,阿里云没有默认密码,如果购买时没设置需要先重置实例密码,Windows用户名是administrator,Linux账号是root,阿小云来详细说下阿里云服务器远程登录连接用户名和密码查询方法
22513 0
如何设置阿里云服务器安全组?阿里云安全组规则详细解说
阿里云安全组设置详细图文教程(收藏起来) 阿里云服务器安全组设置规则分享,阿里云服务器安全组如何放行端口设置教程。阿里云会要求客户设置安全组,如果不设置,阿里云会指定默认的安全组。那么,这个安全组是什么呢?顾名思义,就是为了服务器安全设置的。安全组其实就是一个虚拟的防火墙,可以让用户从端口、IP的维度来筛选对应服务器的访问者,从而形成一个云上的安全域。
21045 0
使用SSH远程登录阿里云ECS服务器
远程连接服务器以及配置环境
14861 0
阿里云服务器安全组设置内网互通的方法
虽然0.0.0.0/0使用非常方便,但是发现很多同学使用它来做内网互通,这是有安全风险的,实例有可能会在经典网络被内网IP访问到。下面介绍一下四种安全的内网互联设置方法。 购买前请先:领取阿里云幸运券,有很多优惠,可到下文中领取。
23156 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,云吞铺子总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系统盘、创建快照、配置安全组等操作如何登录ECS云服务器控制台? 1、先登录到阿里云ECS服务器控制台 2、点击顶部的“控制台” 3、通过左侧栏,切换到“云服务器ECS”即可,如下图所示 通过ECS控制台的远程连接来登录到云服务器 阿里云ECS云服务器自带远程连接功能,使用该功能可以登录到云服务器,简单且方便,如下图:点击“远程连接”,第一次连接会自动生成6位数字密码,输入密码即可登录到云服务器上。
36553 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
17515 0
+关注
程序员鸭哥
微信公众号:鸭哥聊Java
90
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载