为什么Joda对象是不可变的?

时间:2012-09-20 18:26:56

标签: java jodatime

我已经读过,Java版本小于7,Joda Time对象比Java的内置函数更可靠。一个引用的原因是Joda对象是不可变的。为什么这有益?如果我想更改Joda DateTime对象的年,小时和时区,我需要制作三份副本!

5 个答案:

答案 0 :(得分:18)

  

如果我想更改Joda DateTime对象的年,小时和时区,我需要制作三份副本!

是的,的确如此。或者,您可以使用旧对象中的所有字段创建一个新对象。

这是一件非常好的事情 - 因为它意味着当你想要依赖一个不改变的物体时,它就不会。考虑这个伪代码:

private static final Instant EARLIEST_ALLOWED_ARTICLE = ...;

private Instant creationTimestamp;

public Article(Instant creationTimestamp, ...) {
    if (creationTimestamp.isBefore(EARLIEST_ALLOWED_ARTICLE)) {
        throw new IllegalArgumetnException(...);
    }
    this.creationTimestamp = creationTimestamp;
    ...
}

没关系,因为Instant是不可变的。如果它是可变的,那么构造函数中的验证将毫无价值 - 除非你在那时创建了一个防御性副本。

根据我的经验,您希望传递引用并知道值的变化不会超过您想要实际更改现有对象的变化,因此不变性会导致更少的错误(使用可变对象可以忘记获取副本,然后任何验证都没用)并且制作的副本更少。

基本上,它允许您在没有复制您接受和存储的所有内容或返回其他代码的情况下推断您的代码本地。当只有您的代码可以改变对象的状态时,弄清楚随着时间的推移会发生什么变得更加简单。

Joda Time实际上有些失败,因为它有可变的不可变类型 - 如果你只是编程到界面(例如ReadableInstant)那么你不要获得这些保证。这就是为什么在Noda Time中我使所有类型真正不可改变。

出于兴趣,您希望String是否可变?如果没有,请尝试考虑这两种情况之间是否存在真正的差异。

答案 1 :(得分:3)

最简单的答案是,一旦创建了一个对象,就会知道无法更改。这意味着您不会遇到数据以意外方式发生变化的情况(可能在代码的其他部分或不同的线程中)。

这使得对象的行为更具可预测性和可靠性。

答案 2 :(得分:1)

可能有很多原因,但有一个好的原因是哈希。不可变对象可用于散列数据结构(例如HashSet,HashMaps中的键等),因为它们的散列码和“相等”语义不会改变。可变对象不适合散列,因为突变可能会改变其哈希码或相等。

通过使Joda日期不可变,它们现在可用于散列数据结构。

答案 3 :(得分:1)

我认为这是由于:

想象一下,你有一个java.util.Date-object,它在多个类中使用。我正在开发一个类,你在另一个类。然后,我决定我需要预测未来,但是我没有创建一个新的Date对象,而是采用我已经拥有的那个,你认为代表某个时间点的那个,并且我增加了三个小时。现在,您的代码可能会在运行时遇到严重问题。使用不可变对象都可以避免这种情况,因为你不能改变它的状态,你不能把它搞砸给别人。

答案 4 :(得分:1)

不幸的是,DateTime的实现不是不可变的[1],因为没有使用final

https://github.com/JodaOrg/joda-time/blob/master/src/main/java/org/joda/time/DateTime.java

[1]术语“不可变”通常被理解为“线程安全不可变”。