系统错误null是什么意思_为什么NULL是错误的?

系统错误null是什么意思_为什么NULL是错误的?

系统错误null是什么意思

Java中NULL用法的简单示例:

public Employee getByName(String name) {

int id = database.find(name);

if (id == 0) {

return null;

}

return new Employee(id);

}

这种方法有什么问题?

它可能返回NULL而不是对象-这是错误的。 在面向对象的范例中, NULL是一种可怕的做法,应不惜一切代价避免使用NULL 。 已经有一些关于这个意见已经发布,包括空引用,数十亿美元的错误由Tony Hoare的介绍和整个对象思想由大卫-韦斯特的书。

在这里,我将尝试总结所有的参数,并举例说明如何避免使用NULL并使用适当的面向对象的结构代替它们。

基本上,可以使用NULL两种替代方法。

第一个是Null Object设计模式(最好的方法是使其成为常数):

public Employee getByName(String name) {

int id = database.find(name);

if (id == 0) {

return Employee.NOBODY;

}

return Employee(id);

}

第二种可能的替代方法是在无法返回对象时抛出异常 ,从而快速失败 :

public Employee getByName(String name) {

int id = database.find(name);

if (id == 0) {

throw new EmployeeNotFoundException(name);

}

return Employee(id);

}

现在,让我们看看反对NULL的参数。

除了上面提到的Tony Hoare的演示文稿和David West的书以外,我在写这篇文章之前阅读了这些出版物:Robert Martin的Clean Code ,Steve McConnell的Code Complete ,John Sonmez的“ No”到“ Null” , 是否返回无效的不良设计? StackOverflow上的讨论。

临时错误处理

每次获取对象作为输入时,都必须检查它是否为NULL或有效的对象引用。 如果忘记检查,则NullPointerException (NPE)可能会在运行时中断执行。 因此,您的逻辑将受到多次检查以及if / then / else分支的污染:

// this is a terrible design, don't reuse

Employee employee = dept.getByName("Jeffrey");

if (employee == null) {

System.out.println("can't find an employee");

System.exit(-1);

} else {

employee.transferTo(dept2);

}

这就是应该用C和其他命令式程序语言处理异常情况的方式。 OOP引入了异常处理,主要是为了摆脱这些临时的错误处理块。 在OOP中,我们让异常冒泡直到它们到达应用程序范围的错误处理程序,并且我们的代码变得更加简洁明了:

dept.getByName("Jeffrey").transferTo(dept2);

考虑NULL引用是过程编程的继承,请改用1)Null对象或2)异常。

模棱两可的语义

为了明确传达其含义,必须将函数getByName()命名为getByNameOrNullIfNotFound() 。 每个返回对象或NULL函数都应该发生相同的情况。 否则,代码阅读器不可避免地会产生歧义。 因此,为了保持语义的明确性,应为函数指定更长的名称。

要摆脱这种歧义,请始终返回真实对象,空对象或引发异常。

有人可能会争辩说,为了性能起见,我们有时必须返回NULL 。 例如,当地图中没有这样的项目时,Java中接口Map get()方法将返回NULL :

Employee employee = employees.get("Jeffrey");

if (employee == null) {

throw new EmployeeNotFoundException();

}

return employee;

由于Map使用NULL ,因此此代码仅搜索地图一次。 如果我们将Map重构,以便其方法get()在未找到任何内容的情况下将引发异常,则我们的代码将如下所示:

if (!employees.containsKey("Jeffrey")) { // first search

throw new EmployeeNotFoundException();

}

return employees.get("Jeffrey"); // second search

显然,这种方法的速度是第一种方法的两倍。 该怎么办?

Map界面(对其作者没有冒犯)具有设计缺陷。 它的方法get()应该一直返回一个Iterator以便我们的代码如下所示:

Iterator found = Map.search("Jeffrey");

if (!found.hasNext()) {

throw new EmployeeNotFoundException();

}

return found.next();

顺便说一句,这正是C ++ STL map :: find()方法的设计方式。

计算机思维与对象思维

有人知道Java中的对象是指向数据结构的指针,而NULL是指向0x00000000的指针(在Intel x86处理器中为0x00000000 if (employee == null)可以理解if (employee == null)语句。

但是,如果您开始将其作为一个对象来考虑,那么这种说法就没有意义了。 这是从对象角度看我们的代码的样子:

- Hello, is it a software department?

- Yes.

- Let me talk to your employee "Jeffrey" please.

- Hold the line please...

- Hello.

- Are you NULL?

对话中的最后一个问题听起来很奇怪,不是吗?

相反,如果他们在我们请求与Jeffrey通话后挂断电话,则会给我们造成麻烦(异常)。 那时,我们尝试再次致电或通知主管,我们无法联系Jeffrey并完成更大的交易。

或者,他们可以让我们与不是Jeffrey的其他人交谈,但是可以帮助我们解决大多数问题,或者在我们需要“特定于Jeffrey”的东西时拒绝帮助(空对象)。

缓慢失败

上面的代码不是快速失败 ,而是尝试缓慢消失,并杀死其他人。 它没有让所有人都知道出了什么问题并且应该立即开始异常处理,而是向客户端隐藏了此故障。

该参数与上面讨论的“临时错误处理”非常接近。

最好使代码尽可能脆弱,让代码在必要时中断。

使您的方法对它们操作的数据极为苛刻。 如果提供的数据不足或根本不适合该方法的主要使用场景,请让他们通过引发异常来抱怨。

否则,返回一个Null对象,该对象暴露出一些常见行为,并在所有其他调用上引发异常:

public Employee getByName(String name) {

int id = database.find(name);

Employee employee;

if (id == 0) {

employee = new Employee() {

@Override

public String name() {

return "anonymous";

}

@Override

public void transferTo(Department dept) {

throw new AnonymousEmployeeException(

"I can't be transferred, I'm anonymous"

);

}

};

} else {

employee = Employee(id);

}

return employee;

}

可变和不完整的对象

通常, 强烈建议设计时牢记不变性的对象。 这意味着对象在实例化过程中会获得所有必需的知识,并且在整个生命周期中都不会改变其状态。

通常,在延迟加载中使用NULL值,以使对象不完整且可变。 例如:

public class Department {

private Employee found = null;

public synchronized Employee manager() {

if (this.found == null) {

this.found = new Employee("Jeffrey");

}

return this.found;

}

}

该技术尽管被广泛使用,但在OOP中却是一种反模式。 主要是因为它使对象负责计算平台的性能问题,而这是Employee对象不应该意识到的。

对象不必管理状态并公开其与业务相关的行为,而必须处理其自身结果的缓存-这就是延迟加载的意义所在。

缓存不是员工在办公室里做的事情,对吗?

解决方案? 请勿以上述原始方式使用延迟加载。 相反,请将此缓存问题移至应用程序的另一层。

例如,在Java中,您可以使用面向方面的编程方面。 例如, jcabi-aspects具有@Cacheable批注,用于缓存方法返回的值:

import com.jcabi.aspects.Cacheable;

public class Department {

@Cacheable(forever = true)

public Employee manager() {

return new Employee("Jacky Brown");

}

}

我希望这种分析令人信服,您将停止NULL您的代码!

相关文章

您可能还会发现以下有趣的帖子:

Java代码中的典型错误 实用程序类的OOP替代 避免字符串串联 对象应该是不可变的

翻译自: https://www.javacodegeeks.com/2014/09/why-null-is-bad.html

系统错误null是什么意思

相关阅读

bt365体育在线 旅游攻略导航

旅游攻略导航

365娱乐app官方版下载 【奥迪A9】新奥迪奥迪A9报价

【奥迪A9】新奥迪奥迪A9报价

365dots 芊用于女孩名字寓意

芊用于女孩名字寓意

365娱乐app官方版下载 国家队守门员名单(中国国家男子足球队历届门将都有哪些)

国家队守门员名单(中国国家男子足球队历届门将都有哪些)

365娱乐app官方版下载 详细步骤教你如何在手机和电脑上安装QQ并快速上手

详细步骤教你如何在手机和电脑上安装QQ并快速上手

bt365体育在线 《何以笙箫默》中,何以琛和赵默笙分别是什么星座?

《何以笙箫默》中,何以琛和赵默笙分别是什么星座?

bt365体育在线 惠威M3A评测 释放中国好声音

惠威M3A评测 释放中国好声音

365娱乐app官方版下载 陈赫虎牙tv官方直播地址详情

陈赫虎牙tv官方直播地址详情

bt365体育在线 怎么在微信群里@所有人?微信群@所有人方法

怎么在微信群里@所有人?微信群@所有人方法