How to handle null pointer and what is “null safe” way to code?
我是初级开发人员,我用Java做网站开发。我知道建议使用org.apache.common.lang.stringutils,因为它的安全性为空。但是什么是空安全或空安全正确性?为什么下面的代码很难看?
if( sth != null ) {
...
}
号
I know
org.apache.common.lang.StringUtils is recommended because of its null safety.
号
对于最基本的字符串操作,通常使用字符串值,代码中会充满
Apache编写了大量Java代码,因此它已经竭尽全力为公共操作提供帮助实用程序。
例如:
1 2 3 4 | int i = s.indexOf('foo'); // Can throw NullPointerException! String b = s.toUpperCase(); // Can throw NullPointerException!! if (s.equals('bar') // Can throw NullPointerException!!! // ... |
如果你开始阅读StringUtils类,你会发现
来自apache.org:
"StringUtils handles null input Strings quietly. That is to say that a null input will return null. Where a boolean or int is being returned details vary by method"
号
根据我的经验,使用
对于初学者到中级程序员来说,这是最常见的问题:他们要么不知道,要么不信任他们正在参与的契约,并且防御性地检查空值。好的。
为什么下面的代码很难看?好的。
1 | if( sth != null ) { ... } |
这并不像你所知道的那么难看,但我们认为如果在项目中有大量的
但是什么是空安全或空安全正确性?< BR>下面是我根据我的经验丰富和最喜欢的作者建议的"
(1)返回空数组或集合,而不是空值(有效Java(参见项目43)- Joshua Bloch)好的。
1 2 3 4 5 6 7 8 9 10 | // The right way to return an array from a collection private final List<Cheese> cheesesInStock = ...; private static final Cheese[] EMPTY_CHEESE_ARRAY = new Cheese[0]; /** * @return an array containing all of the cheeses in the shop. */ public Cheese[] getCheeses() { return cheesesInStock.toArray(EMPTY_CHEESE_ARRAY); } |
号
以类似的方式,可以使集合值方法返回相同的每次需要返回空集合时都是不可变的空集合。
好的。
1 2 3 4 5 6 7 | // The right way to return a copy of a collection public List<Cheese> getCheeseList() { if (cheesesInStock.isEmpty()) return Collections.emptyList(); // Always returns same list else return new ArrayList<Cheese>(cheesesInStock); } |
总之,没有理由从
(2)不返回空值-(清除代码-Bob叔叔)
在许多情况下,特殊情况对象是一种简单的补救方法。假设您有这样的代码:好的。
1 2 3 4 5 6 | List<Employee> employees = getEmployees(); if (employees != null) { for(Employee e : employees) { totalPay += e.getPay(); } } |
。
现在,
1 2 3 4 | List<Employee> employees = getEmployees(); for(Employee e : employees) { totalPay += e.getPay(); } |
幸运的是,
1 2 3 4 | public List<Employee> getEmployees() { if( .. there are no employees .. ) return Collections.emptyList(); } |
。
如果您这样编码,您将最小化
不要传递空值< BR>从方法返回
让我们看一个例子来了解原因。下面是一个计算两点公制的简单方法:
好的。
1 2 3 4 5 6 7 |
。
当有人把
1 |
当然,我们会得到一辆
我们怎么修?我们可以创建一个新的异常类型并抛出它:
好的。
1 2 3 4 5 6 7 8 9 10 |
。
< BR>这样更好吗?它可能比
还有另一种选择。我们可以使用一组断言:
好的。
1 2 3 4 5 6 7 8 |
这是很好的文档,但不能解决问题。如果有人通过NULL,我们仍然会有一个
附加说明:
(1)使用空对象模式(旧方法)
例如(假设您使用DAO模式访问数据库)
您需要做的只是返回一个空对象-比如说您的DAO中的一个客户条目,比如……好的。
1 | if (result == null) { return new EmptyUser(); } |
号
其中,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | public class User { private int id; private String name; private String gender; public String getName() { //Code here } public void setName() { //Code here } } public class EmptyUser extends User { public int getId() { return -1; } public String getName() { return String.Empty(); } } public User getEntry() { User result = db.query("select from users where id = 1"); if(result == null) { return new EmptyUser(); } else { return result; } } |
(2)使用Java 8可选的
事实上,引入
根据新的
2.1。
从
下面是一个示例,说明如何在非空返回案例中使用它:好的。
1 2 3 4 | public Optional<MyEntity> findMyEntity() { MyEntity entity = // some query here return Optional.ofNullable(entity); } |
。
< BR>2.2。在
在
下面是一个示例,说明如何在非空返回案例中使用它:好的。
1 2 3 4 | public Optional<MyEntity> findMyEntity() { MyEntity entity = // some query here return Optional.fromNullable(entity); } |
< BR>好的。
空对象模式对
我肯定更喜欢
BR/>我甚至会说,在EDCOX1 8中,空对象模式不再有任何意义,它过时了,EDOCX1,14是未来。如果你稍微检查一下Java 9中的新内容,你会看到Oracle使EDCOX1 14更进一步,读这篇文章。好的。好啊.
空指针可以说是最常见的运行时崩溃源——它们实际上是定时炸弹。Java中可怕的null检查被大多数高级开发人员认为是代码的气味,通常是设计糟糕的标志。
更安全的方法是使用一个如zhc所提到的空对象模式。在这种情况下,每当您声明一个未初始化的对象时,都会创建它,而不是让它作为一个空对象一直保持到填充为止。
一个过于简单的例子就是总是用"来实例化一个字符串。空标签(在我看来)比撞车好。
带有空检查的代码并不难看。例如,如果您使用C语言或GO语言检查某些代码,它们将充满空检查。还有,关于你的"零安全"方式。我认为这是某种使用GOF中的空对象模式的方法。