我已经读过,Java 版本低于 7,Joda Time 对象比 Java 的内置对象更可靠。一个被引用的原因是 Joda 对象是不可变的。为什么这是有益的?如果我想更改 Joda DateTime 对象的年、小时和时区,我需要制作三份!
5 回答
如果我想更改 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
可变吗?如果没有,请尝试考虑这两种情况之间是否存在真正的差异。
最简单的答案是,一旦你创建了一个对象,你就知道它不能改变。这意味着您不会遇到数据以意外方式更改的情况(可能在代码的其他部分或不同的线程中)。
这使得对象的行为更加可预测和可靠。
不幸的是,DateTime 的实现不是不可变的[1],因为没有final
使用。
https://github.com/JodaOrg/joda-time/blob/master/src/main/java/org/joda/time/DateTime.java
[1] 术语“不可变”通常被理解为“线程安全的不可变”。
可能有很多原因,但一个很好的原因是关于散列。不可变对象可用于散列数据结构(例如 HashSet、HashMap 中的键等),因为它们的散列码和“相等”语义不会改变。可变对象不适合散列,因为突变可能会改变它们的散列码或相等性。
通过使 Joda 日期不可变,它们现在可以用于散列数据结构。
我认为这是由于:
想象一下,您有一个 java.util.Date 对象,它在多个类中使用。我在一个课程上做开发,你在另一个课程上。然后,我决定我需要预测未来,但我没有创建一个新的日期对象,而是取我已经拥有的那个,你认为代表某个时间点的那个,然后我增加了三个小时。现在,您的代码可能会在运行时遇到严重问题。这一切都可以使用不可变对象来避免,因为你不能改变它的状态,你不能为其他人搞砸它。