问题描述
我是一名初级开发人员,并且使用Java进行网站开发.我知道建议使用org.apache.common.lang.StringUtils,因为它具有null安全性.但是什么是零安全或零安全?为什么下面的代码很难看?
I am a junior developer and I use java to do website development.I know org.apache.common.lang.StringUtils is recommended because of its null safty.But what is null safe or null safty exacty?why the codes as follows is ugly?
推荐答案
这是初学者到中级程序员最常见的问题:他们要么不知道,要么不信任自己所参与的合同以及在防御上的合同检查是否为空.
This is the most common problem to beginner to intermediate level programmer: they either don't know or don't trust the contracts they are participating in and defensively over check for nulls.
为什么以下代码很难看?
if( sth != null ) { ... }
这并不像您所知道的那么丑陋,但是如果我们在项目中有很多 null
检查条件,我们认为这是额外的检查,而不是可读的代码.(对于这种情况,如果您接受null表示合同中的有效回复;并且...)
It's not ugly as much as you know , but we thought it's extra check and not readable code if we have alot of null
check condition in project. (For the case, if you accept where null is a valid response in terms of the contract; and ...)
但是什么是零安全或零安全?
以下是我根据经验丰富和喜欢的作者建议的"空
安全"编码方式.
(1)返回空数组或集合,而不是空值(有效的Java语言(请参见条款43)-Joshua Bloch)
(1) Return empty arrays or collections, not nulls (Effective Java (See Item 43) - Joshua Bloch )
// 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);
}
以类似的方式,可以使集合值的方法返回相同的值不变的空集合,每次需要返回一个空集合时. Collections.emptySet
, emptyList
和 emptyMap方法
完全提供了您所需的内容,如下所示:
In similar fashion, a collection-valued method can be made to return the sameimmutable empty collection every time it needs to return an empty collection. The Collections.emptySet
, emptyList
, and emptyMapmethods
provide exactly what you need, as shown below:
// 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);
}
总而言之,没有理由从 array
-返回 null
或 collection
值方法,而不是返回空数组或collection.
In summary, there is no reason ever to return null
from an array
- orcollection
-valued method instead of returning an empty array or collection.
(2)不要返回空值-(清除代码-Bob叔叔)
在许多情况下,特殊情况的对象很容易补救.假设您有这样的代码:
(2) Don't Return Null - (Clean Code - Uncle Bob)
In many cases, special case objects are an easy remedy. Imagine that you have code like this:
List<Employee> employees = getEmployees();
if (employees != null) {
for(Employee e : employees) {
totalPay += e.getPay();
}
}
现在, getEmployees
可以返回 null
,但是必须这样做吗?如果我们更改 getEmployeeso
使其返回一个空列表,我们可以清理代码:
Right now, getEmployees
can return null
, but does it have to? If we change getEmployeeso
that it returns an empty list, we can clean up the code:
List<Employee> employees = getEmployees();
for(Employee e : employees) {
totalPay += e.getPay();
}
幸运的是, Java
具有 Collections.emptyList()
,,它返回一个预定义的不可变列表,我们可以将其用于此目的:
Fortunately, Java
has Collections.emptyList()
, and it returns a predefined immutable list that we can use for this purpose:
public List<Employee> getEmployees() {
if( .. there are no employees .. )
return Collections.emptyList();
}
如果使用这种方式进行编码,则将最大限度地减少 NullPointerExceptions
的机会,并且代码将更加简洁.
If you code this way, you will minimize the chance of NullPointerExceptions
and your code will be cleaner.
不传递空值
从方法中返回 null
是不好的,但是将 null
传递给方法则更糟.除非您使用的是 API (希望您传递 null
),否则应尽可能避免在代码中传递 null
.
让我们看一个例子,看看为什么.这是一种简单的方法,可针对两点计算指标:
Don’t Pass Null
Returning null
from methods is bad, but passing null
into methods is worse. Unless you are working with an API which expects you to pass null
, you should avoid passing null
in your code whenever possible.
Let’s look at an example to see why. Here is a simple method which calculates a metric for two points:
public class MetricsCalculator
{
public double xProjection(Point p1, Point p2) {
return (p2.x – p1.x) * 1.5;
}
…
}
当有人通过 null
作为参数时会发生什么?
What happens when someone passes null
as an argument?
calculator.xProjection(null, new Point(12, 13));
我们当然会得到一个 NullPointerException
.
我们该如何解决?我们可以创建一个新的异常类型并将其抛出:
How can we fix it? We could create a new exception type and throw it:
public class MetricsCalculator
{
public double xProjection(Point p1, Point p2) {
if (p1 == null || p2 == null) {
throw InvalidArgumentException(
"Invalid argument for MetricsCalculator.xProjection");
}
return (p2.x – p1.x) * 1.5;
}
}
这是否更好?它可能比 nullpointerexception
好一点,但是请记住,我们必须为 InvalidArgumentException
定义一个处理程序.处理程序应该怎么做?有什么好的做法吗?
还有另一种选择.我们可以使用一组断言:
Is this better? It might be a little better than a nullpointerexception
, but remember, we have to define a handler for InvalidArgumentException
. What should the handler do? Is there any good course of action?
There is another alternative. We could use a set of assertions:
public class MetricsCalculator
{
public double xProjection(Point p1, Point p2) {
assert p1 != null : "p1 should not be null";
assert p2 != null : "p2 should not be null";
return (p2.x – p1.x) * 1.5;
}
}
这是很好的文档,但并不能解决问题.如果有人传递null,我们仍然会出现 runtime
错误.
在大多数编程语言中,没有很好的方法来处理 null
被呼叫者不小心经过.因为是这种情况,所以合理的方法是默认情况下禁止传递空值.当您这样做时,您可以知道在参数列表中的 null
表示存在问题,并且最终会产生更少的粗心的错误.
It’s good documentation, but it doesn’t solve the problem. If someone passes null, we’ll still have a runtime
error.
In most programming languages there is no good way to deal with a null
that ispassed by a caller accidentally. Because this is the case, the rational approach is to forbid passing null by default. When you do, you can code with the knowledge that a null
in an argument list is an indication of a problem, and end up with far fewer careless mistakes.
附加说明: null
-return习惯用法可能是 C编程语言的保留项,在该语言中,数组长度与实际数组分开返回.在 C 中,如果返回的长度为零,则分配数组没有任何好处.
Extra Note:The null
-return idiom is likely a holdover from the C programming language, in which array lengths are returned separately from actual arrays. In C, there is no advantage to allocating an array if zero is returned as the length.
(1)使用空对象模式 (旧方法)
例如.(假设您使用的是dao模式访问数据库)
您需要做的就是返回一个空对象-说您要在 DAO 中输入的客户条目,例如.....
(1) Use Null Object Pattern (old approach)
eg.(assume you are using dao pattern to access db)
All you need to do is return an empty object - say a customer entry you would have in your DAO something like.....
if (result == null) { return new EmptyUser(); }
其中 EmptyUser
扩展 User
并返回适当的条目以进行getter调用,以使其余代码知道它是一个空对象(id = -1等)代码示例:
where EmptyUser
extends User
and returns appropriate entries to getter calls to allow the rest of your code to know it is an empty object (id = -1 etc)code sample:
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可选
实际上,引入 null
引用可能是编程语言历史上最严重的错误之一,即使其创建者 Tony Hoare 称它为他的十亿美元错误.
(2) Use Java 8 Optional
Indeed introducing null
reference is probably one of the worse mistake in the programming languages' history even its creator Tony Hoare calls it his billion-dollar mistake.
根据新的 Java
版本,以下是 null
的最佳替代方法:
Here are the best alternatives to null
according to new Java
version:
2.1. Java 8
及更高版本
2.1. Java 8
and above
从 Java 8
开始,您可以使用 java.util.可选.
以下是在非null返回情况下如何使用它的示例:
Here is an example of how you could use it in not null return case:
public Optional<MyEntity> findMyEntity() {
MyEntity entity = // some query here
return Optional.ofNullable(entity);
}
2.2.在 Java 8
2.2. Prior to Java 8
在 Java 8
之前,您可以使用 com.google.common.base.可选(来自Google Guava).
Before Java 8
you can use com.google.common.base.Optional from Google Guava.
以下是在非null返回情况下如何使用它的示例:
Here is an example of how you could use it in not null return case:
public Optional<MyEntity> findMyEntity() {
MyEntity entity = // some query here
return Optional.fromNullable(entity);
}
空对象模式注释与 Java 8可选
:
Note for Null Object Pattern Vs Java 8 Optional
:
我肯定更喜欢 Optional
,它更通用 generic
,并且已被 Oracle和Google(这两家最大的IT公司中的两家)采用这个世界功不可没.
我什至会说空对象模式在 Java
中不再有意义,它已经过时了, Optional
是未来,如果您稍微了解一下Java 9的新功能,您会发现 Oracle 使 Optional
更加深入,请阅读本文
I definitively prefer Optional
it is much more generic
and it has been adopted by Oracle and Google, 2 of the biggest IT companies in the world which give a lot of credits to it.
I would even say that Null Object Pattern doesn't make any sense anymore in Java
, it is outdated, Optional
is the future if you check a little bit what's new in Java 9, you will see that Oracle makes Optional
go a little bit further, read this article
这篇关于如何处理空指针以及什么是“空安全"?编码方式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!