Java 如何处理空指针以及什么是;“零安全”;编码方式?

Java 如何处理空指针以及什么是;“零安全”;编码方式?,java,null,Java,Null,我是一名初级开发人员,我使用java进行网站开发。 我知道org.apache.common.lang.StringUtils是推荐的,因为它具有空安全性。 但究竟什么是零安全或零安全呢? 为什么下面的代码很难看 如果(某事物)为空{ ... } 带有空检查的代码并不难看。例如,如果您在C或Go语言中检查一些代码,它们都充满了空检查。 还有,关于你的“零安全”方式。我认为这是GoF的某种使用模式。空指针可以说是运行时崩溃的最常见来源——它们实际上是定时炸弹。java中可怕的空检查被大多数高级开发

我是一名初级开发人员,我使用java进行网站开发。 我知道org.apache.common.lang.StringUtils是推荐的,因为它具有空安全性。 但究竟什么是零安全或零安全呢? 为什么下面的代码很难看

如果(某事物)为空{ ... }


带有空检查的代码并不难看。例如,如果您在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!!!
   // ...