Java 如何处理空指针以及什么是;“零安全”;编码方式?
我是一名初级开发人员,我使用java进行网站开发。 我知道org.apache.common.lang.StringUtils是推荐的,因为它具有空安全性。 但究竟什么是零安全或零安全呢? 为什么下面的代码很难看 如果(某事物)为空{ ... }Java 如何处理空指针以及什么是;“零安全”;编码方式?,java,null,Java,Null,我是一名初级开发人员,我使用java进行网站开发。 我知道org.apache.common.lang.StringUtils是推荐的,因为它具有空安全性。 但究竟什么是零安全或零安全呢? 为什么下面的代码很难看 如果(某事物)为空{ ... } 带有空检查的代码并不难看。例如,如果您在C或Go语言中检查一些代码,它们都充满了空检查。 还有,关于你的“零安全”方式。我认为这是GoF的某种使用模式。空指针可以说是运行时崩溃的最常见来源——它们实际上是定时炸弹。java中可怕的空检查被大多数高级开发
带有空检查的代码并不难看。例如,如果您在C或Go语言中检查一些代码,它们都充满了空检查。
还有,关于你的“零安全”方式。我认为这是GoF的某种使用模式。空指针可以说是运行时崩溃的最常见来源——它们实际上是定时炸弹。java中可怕的空检查被大多数高级开发人员认为是一种代码味道,通常是设计糟糕的标志 一种更安全的方法是使用zhc提到的空对象模式。在这种情况下,无论何时声明一个未初始化的对象,都要创建它,而不是让它在填充之前一直作为null
一个过于简化的例子是总是用“”实例化字符串。空标签(在我看来)比崩溃更可取。这是初学者到中级程序员最常见的问题:他们要么不知道,要么不信任他们正在参与的契约,并防御性地检查空标签 为什么下面的代码很难看?
if( sth != null ) { ... }
它并不像你们所知道的那个样难看,但我们认为它是额外的检查,若我们在项目中有大量的null
check条件,那个么代码就不可读了。(在这种情况下,如果您接受合同条款中的无效回复;以及……)
但是什么是零安全或零安全呢?下面是我根据我经验丰富且最喜欢的作者的建议,对“
null
safe”编码方式的建议
对于集合对象案例
(1)返回空数组或集合,而不是null(有效Java(参见第43项)-Joshua Bloch)
总之,没有任何理由从数组返回null
-或
集合
值方法,而不是返回空数组或集合
(2)不要返回Null-(干净的代码-Bob叔叔)
在许多情况下,特例对象是一种简单的补救方法。假设您有这样的代码:
List<Employee> employees = getEmployees();
if (employees != null) {
for(Employee e : employees) {
totalPay += e.getPay();
}
}
幸运的是,Java
拥有Collections.emptyList()
,,它返回一个预定义的不可变列表,我们可以用于此目的:
public List<Employee> getEmployees() {
if( .. there are no employees .. )
return Collections.emptyList();
}
当有人将null
作为参数传递时会发生什么情况?
calculator.xProjection(null, new Point(12, 13));
当然,我们会得到一个NullPointerException
我们怎样才能修复它?我们可以创建一个新的异常类型并抛出它:
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
定义一个处理程序。处理程序应该做什么?有什么好办法吗
还有另一种选择。我们可以使用一组断言:
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,我们仍然会有一个运行时
错误
在大多数编程语言中,没有处理null的好方法,即
意外地从打电话的人身边经过。因为是这种情况,所以理性的方法是在默认情况下禁止传递null。当您这样做时,您可以在编写代码时知道,参数列表中的null
表示出现了问题,并且最终导致的粗心错误要少得多
额外说明:
null
-return习惯用法可能是C编程语言的延续,在这种语言中,数组长度与实际数组分开返回。在C中,如果返回零作为长度,则分配数组没有任何好处
对于非集合对象案例
(1)使用(旧方法)
例如(假设您正在使用dao模式访问数据库)
您所需要做的就是返回一个空对象——比如说您在DAO中的客户条目
if (result == null) { return new EmptyUser(); }
其中EmptyUser
扩展User
并向getter调用返回适当的条目,以允许代码的其余部分知道它是一个空对象(id=-1等)
代码示例:
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
reference可能是编程语言历史上最严重的错误之一,甚至连它的创建者都称之为他的数十亿美元的错误
根据新的Java
版本,以下是null
的最佳替代方案:
2.1<代码>Java 8
及以上版本
从Java8
开始,您可以使用
下面是一个示例,说明如何在非空返回情况下使用它:
public Optional<MyEntity> findMyEntity() {
MyEntity entity = // some query here
return Optional.ofNullable(entity);
}
public Optional<MyEntity> findMyEntity() {
MyEntity entity = // some query here
return Optional.fromNullable(entity);
}
空对象模式与Java 8可选模式的对比说明:
:
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;
}
}
我当然更喜欢可选
它更像通用
,而且它已经被Oracle和Google所采用,2家世界上最大的it公司对它给予了很大的赞誉我甚至想说空对象模式在
Java
中不再有任何意义,它是过时的,可选的是未来如果你稍微检查一下Java 9中的新功能,你会发现Oracle使可选的更进一步,请阅读
我知道,org.apache.common.lang.StringUtils
是推荐的,因为它具有空安全性
通常对于字符串值,对于最基本的字符串操作,代码将被if(foo!=null){…
所迷惑
Apache编写了大量的代码,因此它已经竭尽全力为常见的opera提供帮助工具
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;
}
}
public Optional<MyEntity> findMyEntity() {
MyEntity entity = // some query here
return Optional.ofNullable(entity);
}
public Optional<MyEntity> findMyEntity() {
MyEntity entity = // some query here
return Optional.fromNullable(entity);
}
int i = s.indexOf('foo'); // Can throw NullPointerException!
String b = s.toUpperCase(); // Can throw NullPointerException!!
if (s.equals('bar') // Can throw NullPointerException!!!
// ...