7

如果我查询一个对象说一个 Animal 并且返回的对象不是 null 但包含 null 变量,那是错误的吗?例如我可以打电话animal.getDeathDate();并且由于它还没有死,所以它返回 null。因为 TurtlegetFlightSpeed()将返回 null,因为在添加 Turtle 火箭包之前它无法飞行。等等等等。

我认为这是一种不好的做事方式,因为在调用对象的方法以验证它们是否包含非空值时,它通常会导致需要进行大量空值检查。是否有任何相关信息的链接可以进一步告知我自己和我的同事?

4

9 回答 9

5

null常常是模棱两可的。该字段是尚未初始化还是没有任何价值?

为未初始化/不相关的字段设置一些预定义的常量通常会更好。

更好的是让一个班级只有一个责任。像这样的方法getFlightSpeed()不应该被继承,而是来自实现一个接口(getDeathDate()不过,像这样的方法应该在Animal仍然存在时返回一个预定义的常量)。

正如 google-guava docs 带来的那样

Doug Lea(java.util.concurrent包的作者)说Null s**ks

参考文献的发明者CAR Hoare 爵士nullI call it my billion-dollar mistake

这是一个宽阔的肩膀。

于 2013-08-05T14:09:02.457 回答
4

返回null一个活着的动物的死亡日期是完全合理的,但在这种情况下,我发现最好提供一个布尔死亡检查:

public boolean isDead() {
    return deathDate != null;
}

这提供了一种合理的方法来检查实例的死亡情况,而无需对属性进行笨拙的 null 检查:

// this is ugly and exposes the choice of the value of the field when alive
if (animal.getDeathDate() != null) {
    // the animal is dead
}

使用该isDead()方法,您将有权执行此操作:

public Date getDeathDate() {
    if (deathDate == null)
        throw new IllegalStateException("Death has not occurred");
    return deathDate;
}

关于乌龟的飞行速度,您可以应用相同的方法,尽管我认为您的类设计存在问题 - 并非所有动物都会飞行,因此Animal该类不应该有getFlyingSpeed()方法。

相反,使用这样的东西:

interface Flyer {
    Integer getFlightSpeed();
}

class Animal {}

class Turtle extends Animal {}

class Eagle extends Animal implements Flyer {
    public Integer getFlightSpeed() {
         //
    }
}
于 2013-08-05T14:10:29.640 回答
1

Null 有时可以是表示对象缺少特定属性的完全合理的方式。

但是,允许单次检查很有用。

对于数组或列表,最好有一个始终为非空但可以指向空列表的变量。否则,有必要检查变量是否为非空以及列表是否有成员。

于 2013-08-05T14:02:56.897 回答
1

我不认为这是错的。打个比方,想想SQL 中 NULL的语义:

记住 NULL 含义的一个好方法是记住,就信息而言,“缺少值”与“值为零”不同;同样,“缺乏答案”与“否定答案”不同。

在 Java 中应用相同的逻辑是完全有效的。

为了使原始类型可以为空,请查看C# 中的可空类型。将 Nullable 实现为 Java 泛型应该很容易。

于 2013-08-05T14:14:00.447 回答
1

我有一个主要的 null 检查规则是永远不要放置 null 而不是列表或数组。

空列表和数组更能更好地表达它们的真实含义。

于 2013-08-05T14:20:40.670 回答
0

这只是我的观点,但您的示例听起来确实像一个反模式(作为退化的空对象),因为您需要对“空对象”上的方法返回的内容进行空检查。如果您根本不调用这些吸气剂,那么您的示例将是正确的。

使用 null 对象的想法是您根本不需要执行 null 检查,因此如果您的 getter 返回其他 null 对象,或者方法使用告诉-不要-询问方法(并且只返回 void) ,它可能会起作用.

于 2013-08-05T14:03:17.760 回答
0

Null 很好,但您应该尽量避免使用默认值

例如,应返回空列表而不是 null 枚举数据类型应包含 UNKNOWN

上述假设使 API 使用者的生活变得轻松

在您的示例中,我会从 animal.getDeathDate 返回 null,因为我想不出任何合适的默认值。

我将提供方便的方法 animal.isDead 返回 true/false

对于 getFlightSpeed() 我会为你的情况返回 0

于 2013-08-05T14:10:52.293 回答
0

在空变量的情况下,确实可以使用空对象模式。在 Turtle.getFlightSpeed() 的情况下,您可以抽象出 SPEED 概念(可能是接口或抽象类),并让一个 NULL 对象实现“无法飞行”的场景。这将有助于将默认行为分配给 Turtle 类。在 animal.getDeathDate() 的情况下返回 null 似乎很好

于 2013-08-05T14:13:22.803 回答
0

我认为对于 animal.getDeathDate() 如果动物还活着返回 null 是正确的做事方式。您将始终需要特殊代码来处理 2 种情况:动物活着和动物死亡,如果动物还活着,则没有可以返回的有用日期。

对于 getFlightSpeed() 事情可能会有所不同。我不确切知道它返回什么,但我们只是举个例子,想象它只是将速度返回为 m/s

在这种情况下,返回 0(或具有相同效果的对象)将非常有意义,因为它确实描述了飞行速度。

于 2013-08-05T14:15:08.890 回答