避免Java应用中NullPointerException的技巧和最佳实践
Java应用中抛出的空指针异常是解决空指针的最好方式,也是写出能顺利工作的健壮程序的关键。俗话说“预防胜于治疗”,对于这么令人讨厌的空指针异常,这句话也是成立的。值得庆幸的是运用一些防御性的编码技巧,跟踪应用中多个部分之间的联系,你可以将Java中的空指针异常控制在一个很好的水平上。
顺便说一句,这是Javarevisited上的第二个空指针异常的帖子。在上个帖子(参见微信尾部的备注)中我们讨论了Java中导致空指针异常的常见原因,而在本教程中我们将会学习一些Java的编程技巧和最佳实践。这些技巧可以帮助你避免Java中的空指针异常。遵从这些技巧同样可以减少Java代码中到处都有的非空检查的数量。
作为一个有经验的Java程序员,你可能已经知道其中的一部分技巧并且应用在你的项目中。但对于新手和中级开发人员来说,这将是很值得学习的。顺便说一句,如果你知道其它的避免空指针异常和减少空指针检查的Java技巧,请和我们分享。
这些都是简单的技巧,很容易应用,但是对代码质量和健壮性有显著影响。根据我的经验,只有第一个技巧可以显著改善代码质量。如我之前所讲,如果你知道任何避免空指针异常和减少空指针检查的Java技巧,你可以通过评论本文来和分享。
1) 从已知的String对象中调用equals()和equalsIgnoreCase()方法,而非未知对象。
总是从已知的非空String对象中调用equals()方法。因为equals()方法是对称的,调用a.equals(b)和调用b.equals(a)是完全相同的,这也是为什么程序员对于对象a和b这么不上心。如果调用者是空指针,这种调用可能导致一个空指针异常

这是避免空指针异常最简单的Java技巧,但能够导致巨大的改进,因为equals()是一个常见方法。
2) 当valueOf()和toString()返回相同的结果时,宁愿使用前者。
因为调用null对象的toString()会抛出空指针异常,如果我们能够使用valueOf()获得相同的值,那宁愿使用valueOf(),传递一个null给valueOf()将会返回“null”,尤其是在那些包装类,像Integer、Float、Double和BigDecimal。

3) 使用null安全的方法和库
有很多开源库已经为您做了繁重的空指针检查工作。其中最常用的一个的是Apache commons 中的StringUtils。你可以使用StringUtils.isBlank(),isNumeric(),isWhiteSpace()以及其他的工具方法而不用担心空指针异常。

但是在做出结论之前,不要忘记阅读空指针方法的类的文档。这是另一个不需要下大功夫就能得到很大改进的Java最佳实践。
4) 避免从方法中返回空指针,而是返回空collection或者空数组。
这个Java最佳实践或技巧由Joshua Bloch在他的书Effective Java中提到。这是另外一个可以更好的使用Java编程的技巧。通过返回一个空collection或者空数组,你可以确保在调用如size(),length()的时候不会因为空指针异常崩溃。Collections类提供了方便的空List,Set和Map: Collections.EMPTY_LIST,Collections.EMPTY_SET,Collections.EMPTY_MAP。这里是实例。

你同样可以使用Collections.EMPTY_SET和Collections.EMPTY_MAP来代替空指针。
5) 使用annotation@NotNull 和 @Nullable
在写程序的时候你可以定义是否可为空指针。通过使用像@NotNull和@Nullable之类的annotation来声明一个方法是否是空指针安全的。现代的编译器、IDE或者工具可以读此annotation并帮你添加忘记的空指针检查,或者向你提示出不必要的乱七八糟的空指针检查。IntelliJ和findbugs已经支持了这些annotation。这些annotation同样是JSR 305的一部分,但即便IDE或工具中没有,这个annotation本身可以作为文档。看到@NotNull和@Nullable,程序员自己可以决定是否做空指针检查。顺便说一句,这个技巧对Java程序员来说相对比较新,要采用需要一段时间。
6) 避免你的代码中不必要的自动包装和自动解包。
且不管其他如创建临时对象的缺点,如果wrapper类对象是null,自动包装同样容易导致空指针异常。例如如果person对象没有电话号码的话会返回null,如下代码会因为空指针异常崩溃。

当使用自动包装和自动解包的时候,不仅仅是等号,<, >, 同样会抛出空指针异常。你可以通过这篇文章(参见微信尾部的备注)来学习更多的Java中的自动包装和拆包的陷阱。
7) 遵从Contract并定义合理的默认值。
在Java中避免空指针异常的一个最好的方法是简单的定义contract并遵从它们。大部分空指针异常的出现是因为使用不完整的信息创建对象或者未提供所有的依赖项。如果你不允许创建不完整的对象并优雅地拒绝这些请求,你可以在接下来的工作者预防大量的空指针异常。类似的,如果对象允许创建,你需要给他们定义一个合理的默认值。例如一个Employee对象不能在创建的时候没有id和name,但是是否有电话号码是可选的。现在如果Employee没有电话号码,你可以返回一个默认值(例如0)来代替返回null。但是必须谨慎选择,哟有时候检查空指针比调用无效号码要方便。同样的,通过定义什么可以是null,什么不能为null,调用者可以作出明智的决定。failing fast或接受null同样是一个你需要进行选择并贯彻的,重要的设计决策
8)定义数据库中的字段是否可为空。
如果你在使用数据库来保存你的域名对象,如Customers,Orders 等,你需要在数据库本身定义是否为空的约束。因为数据库会从很多代码中获取数据,数据库中有是否为空的检查可以确保你的数据健全。在数据空中维护null约束同样可以帮助你减少Java代码中的空指针检查。当从数据库中加载一个对象是你会明确,哪些字段是可以为null的,而哪些不能,这可以使你代码中不必要的!= null检查最少化。
9) 使用空对象模式(Null Object Pattern)
还有一种方法来避免Java中的空指针异常。如果一个方法返回对象,在调用者中执行一些操作,例如Collection.iterator()方法返回迭代器,其调用者执行遍历。假设如果一个调用者并没有任何迭代器,其可以返回空对象(Null object)而非null。空对象是一个特殊的对象,其在不同的上下文中有不同的意义。例如一个空的迭代器调用hasNext()返回false时,可以是一个空对象。同样的在返回Container和Collection类型方法的例子中,空对象可以被用来代替null作为返回值。我打算另写一篇文章来讲空对象模式,分享几个Java空对象的例子。
这就是全部了,这是几个易于遵从的避免空指针异常的Java技巧和最佳实践。你可以欣赏到这些技巧将非常有用,且不太难实现。如果你有其他比秒这个异常的技巧,而又没包含在这里,请通过评论来和我们分享,我将收录在这里。
备注:
由于微信不支持超链接,如果您希望阅读本文中第二自然段提到的"上一篇帖子",以及第6条中提到的"这篇文章",请选择"阅读原文"查看网页版。
避免Java应用中NullPointerException的技巧和最佳实践的更多相关文章
- 避免Java中NullPointerException的Java技巧和最佳实践
Java中的NullPointerException是我们最经常遇到的异常了,那我们到底应该如何在编写代码是防患于未然呢.下面我们就从几个方面来入手,解决这个棘手的问题吧. 值得庆幸的是,通过应用 ...
- SuperDiamond在JAVA项目中的三种应用方法实践总结
SuperDiamond在JAVA项目中的三种应用方法实践总结 1.直接读取如下: @Test public static void test_simple(){ PropertiesConfigur ...
- 【转】超实用的JavaScript技巧及最佳实践
众所周知,JavaScript是一门非常流行的编程语言,开发者用它不仅可以开发出炫丽的Web程序,还可以用它来开发一些移动应用程序(如PhoneGap或Appcelerator),它还有一些服务端实现 ...
- 超实用的JavaScript技巧及最佳实践
众所周知,JavaScript是一门非常流行的编程语言,开发者用它不仅可以开发出炫丽的Web程序,还可以用它来开发一些移动应用程序(如PhoneGap或Appcelerator),它还有一些服务端实现 ...
- 超实用的JavaScript技巧及最佳实践(上)
在这篇文章中,作者将会向大家分享JavaScript开发的小技巧.最佳实践等非常实用的内容,不管你是前端开发者还是服务端开发者,都应该来看看这些小技巧,它们绝对会让你受益的. 文中所提供的代码片段都已 ...
- 《深入理解Java虚拟机:JVM高级特性与最佳实践》【PDF】下载
<深入理解Java虚拟机:JVM高级特性与最佳实践>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062566 内容简介 作为一位 ...
- 读书笔记-《深入理解Java虚拟机:JVM高级特性与最佳实践》
目录 概述 第一章: 走进Java 第二章: Java内存区域与内存溢出异常 第三章: 垃圾收集器与内存分配策略 第四章: 虚拟机性能监控与故障处理 第五章: 调优案例分析与实战 第六章: 类文件结构 ...
- nodejs进阶(1)——npm使用技巧和最佳实践
nodejs进阶教程,小白绕道!!! npm使用技巧和最佳实践 前提:请确保安装了node.js npm的最佳实践 npm install是最常见的npm cli命令,但是它还有更多能力!接下来你会了 ...
- 【转】Java中关于异常处理的十个最佳实践
原文地址:http://www.searchsoa.com.cn/showcontent_71960.htm 导读:异常处理是书写强健Java应用的一个重要部分,Java许你创建新的异常,并通过使用 ...
随机推荐
- python datetime笔记
python datetime笔记 http://mint-green.diandian.com/post/2011-09-09/4892024 获取当前时间,并通过字符串输出. 格式为:%Y-%m- ...
- python中unicode、utf8、gbk等编码问题
转自:http://luchanghong.com/python/2012/07/06/python-encoding-with-unicode-and-gbk-and-utf8.html 概要:编码 ...
- BZOJ 2806 cheat
首先这个题目显然是要二分转换成判断可行性的 之后我们考虑DP 设f(i)表示 1->i 熟悉的子串的长度的最大值 那么对于i这个点,要么不在熟悉的子串中,要么在熟悉的子串中 所以得到 f(i)= ...
- sizeof运算符来获取各种数据类型在内存中所占字节数--gyy整理
C++并没有规定各种数据类型在内存中的存储大小,依赖于不同的编译器的不同而不同,要想获知当前编译器对各种数据类型分配的大小,可以通过sizeof运算符来获取. 使用方法1: sizeof(数据类型) ...
- MySQL 5.6 安装配置
mysql 5.6.17下载安装图解_百度经验 http://jingyan.baidu.com/article/4b07be3c67853c48b380f311.html windows 8 系统将 ...
- POJ1942——Paths on a Grid(组合数学)
Paths on a Grid DescriptionImagine you are attending your math lesson at school. Once again, you are ...
- HDU1875——畅通工程再续(最小生成树:Kruskal算法)
畅通工程再续 Description相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现.现在政府决定大力发展百岛湖,发展首先要解决的问题当 ...
- linux的终端,网络虚拟终端,伪终端(转)
blog.csdn.net/todd911/article/details/8025540 Linux上许多网络服务应用,如l2tp.pptp.telnet,都用到了伪终端.有朋友在问这方面的概念 ...
- HTTP认证方式
HTTP请求报头: Authorization HTTP响应报头: WWW-Authenticate HTTP认证 基于 质询 /回应( challenge/response)的认证模式. ◆ ...
- 【Codeforces】#345 Div1
1. Watchmen1.1 题目描述给$n$个点,求曼哈顿距离等于欧式距离的点对数. 1.2 基本思路由$|x_i-x_j|+|y_i-yj| = \sqrt{(x_i-x_j)^2+(y_i-yj ...