java.util.Date equals()似乎没有按预期工作 [英] java.util.Date equals() doesn't seem to work as expected
问题描述
我有一个 Map< Date,Foo>
,还有一个来自数据库的对象列表使用 effectiveDate
属性,我想检查我的地图中的 Date
键是否等于任何数据库中的 effectiveDate
- 如果是这样的话,用 Foo
做一些事情。
I have a Map<Date, Foo>
, and a list of objects from the database with an effectiveDate
property, and I want to check to see if the Date
keys in my map are equal to any of the effectiveDate
s in the database - if so, do stuff with Foo
.
代码如下所示:
for (Bar bar : databaseBars) {
Foo foo = new Foo();
if (dateMap.containsKey(bar.getEffectiveDate()) {
foo = dateMap.get(bar.getEffectiveDate());
}
// do stuff with foo and bar
}
然而, dateMap.containsKey
call总是返回false,即使我确定它有时会出现。
However, the dateMap.containsKey
call always returns false, even though I'm sure it's sometimes there.
作为一个完整性检查,我打印出日期的长值,以及 equals()
调用的结果和 compareTo ()
call:
As a sanity check, I've printed out the long values of the dates, as well as the results of an equals()
call and a compareTo()
call:
for (Date keyDate : dateMap.keySet()) {
if (keyDate == null) {
continue; // make things simpler for now
}
Date effDate = bar.getEffectiveDate();
String template = "keyDate: %d; effDate: %d; equals: %b; compareTo: %d\n";
System.out.printf(template, keyDate.getTime(), effDate.getTime(), effDate.equals(keyDate), effDate.compareTo(keyDate));
}
结果:
keyDate: 1388534400000; effDate: 1388534400000; equals: false; compareTo: 0
keyDate: 1420070400000; effDate: 1388534400000; equals: false; compareTo: -1
keyDate: 1388534400000; effDate: 1420070400000; equals: false; compareTo: 1
keyDate: 1420070400000; effDate: 1420070400000; equals: false; compareTo: 0
keyDate: 1388534400000; effDate: 1388534400000; equals: false; compareTo: 0
keyDate: 1420070400000; effDate: 1388534400000; equals: false; compareTo: -1
keyDate: 1388534400000; effDate: 1420070400000; equals: false; compareTo: 1
keyDate: 1420070400000; effDate: 1420070400000; equals: false; compareTo: 0
keyDate: 1388534400000; effDate: 1388534400000; equals: false; compareTo: 0
keyDate: 1420070400000; effDate: 1388534400000; equals: false; compareTo: -1
keyDate: 1388534400000; effDate: 1420070400000; equals: false; compareTo: 1
keyDate: 1420070400000; effDate: 1420070400000; equals: false; compareTo: 0
问题
1)不应该等于
和 compareTo
同意吗? (我假设 java.util.Date
的实现至少应该尝试遵循 java.lang.Comparable
)。
Question
1) Shouldn't equals
and compareTo
agree? (I assume the implementation of java.util.Date
at least should try to follow the recommendation of java.lang.Comparable
).
2) The Date#equals
doc says this:
因此,当且仅当getTime方法为两者返回相同的long值时,两个Date对象才相等。
Thus, two Date objects are equal if and only if the getTime method returns the same long value for both.
...看起来 getTime
方法为这两个日期返回相同的长值,但等于
返回false。任何想法为什么会这样?我搜索过高低,但我没有发现任何人描述同样的问题。
...Looks like the getTime
method returns the same long value for both of these dates, yet equal
returns false. Any ideas why this might be happening? I've searched high and low, but I haven't found anyone describing the same problem.
P.S。我坚持使用 java.util.Date
。请不要只推荐JodaTime。
P.S. I'm stuck using java.util.Date
. Please don't just recommend JodaTime.
P.P.S。我意识到我可以改变这段代码的结构,并可能让它运行起来。但这应该有效,我不想只是解决它,除非它是一个已知的问题或其他什么。它只是错误。
P.P.S. I realize I could just change the structure of this code and probably get it working. But this should work, and I don't want to just work around it, unless it's a known issue or something. It just seems wrong.
推荐答案
作为 Mureinik 暗示并且 Sotirios Delimanolis 更具体地指出了问题在于 java.util.Date
的实现。
As Mureinik hinted at and Sotirios Delimanolis pointed out more specifically, the problem here is with the implementation of java.util.Date
.
java.util .Date
在 java.sql
包中扩展了3个类,所有这些类似乎都做类似的事情,并且它们在java中的区别不在于一切都清楚(似乎它们存在的原因只是使java类更准确地与SQL数据类型对齐) - 有关它们差异的更多信息,请查看这个非常详细的答案。
java.util.Date
is extended by 3 classes in the java.sql
package, all of which seem to do similar things and whose distinction in java is not at all clear (seems like the reason for their existence is simply to make java classes which align more accurately to SQL datatypes) - for more information on their differences, check out this very detailed answer.
现在,在一个看似严重的设计缺陷中,有人决定制作 equals()
与 java.sql.Timestamp
- 也就是说, timestamp.equals(date)
即使 date.equals(timestamp)$ c $也可能返回false c>返回true。好主意。
Now, in what seems like a serious design flaw, someone decided to make equals()
asymmetric with java.sql.Timestamp
- that is, timestamp.equals(date)
could return false even if date.equals(timestamp)
returns true. Great idea.
我写了几行,看看哪个 java.sql
类演示了这个荒谬的属性 - 显然它是只需时间戳
。此代码:
I wrote a few lines to see which java.sql
classes demonstrate this ridiculous property - apparently it's just Timestamp
. This code:
java.util.Date utilDate = new java.util.Date();
java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());
System.out.println("sqlDate equals utilDate:\t" + sqlDate.equals(utilDate));
System.out.println("utilDate equals sqlDate:\t" + utilDate.equals(sqlDate));
java.sql.Time time = new java.sql.Time(utilDate.getTime());
System.out.println("time equals utilDate:\t\t" + time.equals(utilDate));
System.out.println("utilDate equals time:\t\t" + utilDate.equals(time));
java.sql.Timestamp timestamp = new java.sql.Timestamp(utilDate.getTime());
System.out.println("timestamp equals utilDate:\t" + timestamp.equals(utilDate));
System.out.println("utilDate equals timestamp:\t" + utilDate.equals(timestamp));
收益率:
sqlDate equals utilDate: true
utilDate equals sqlDate: true
time equals utilDate: true
utilDate equals time: true
timestamp equals utilDate: false
utilDate equals timestamp: true
因为 java.util.HashMap
在 containsKey()$的实现中使用
(而不是 parameter.equals(key)
c $ c> key.equals(参数)
),这个奇怪的结果出现在给定的情况下。
Since java.util.HashMap
uses parameter.equals(key)
in it's implementation of containsKey()
(rather than key.equals(parameter)
), this one strange result shows up in the given situation.
那么,如何解决这个问题呢?
So, how to get around this?
1)使用 Long
键在地图而不是日期
(如Mureinik所说) - 因为 java.util.Date
和 java.util.Timestamp
返回相同的内容来自 getTime()
的值,无论你使用哪种实现,关键都是一样的。这种方式看似最简单。
1) Use a Long
key in the map rather than a Date
(as Mureinik noted) - since java.util.Date
and java.util.Timestamp
return the same value from getTime()
, it shouldn't matter which implementation you're using, the key will be the same. This way does seem like the simplest.
2)在地图中使用之前标准化日期对象。这种方式需要更多的工作,但对我来说似乎更可取,因为它更清楚地图是什么 - 一堆 Foo
每一个都存储在一个时刻。这是我最终使用的方式,使用以下方法:
2) Standardize the date object before using it in the map. This way requires a tiny bit more work, but to me seems more desirable as it's more clear what the map is - a bunch of Foo
each stored against a moment in time. This is the way I ended up using, with the following method:
public Date getStandardizedDate(Date date) {
return new Date(date.getTime());
}
这需要一个额外的方法调用(有点可笑的方法) ,但对我而言,涉及 Map< Date,Foo>
的代码的可读性增加是值得的。
It takes an extra method call (and kind of a ridiculous one at that), but to me the increased readability of the code involving the Map<Date, Foo>
is worth it.
这篇关于java.util.Date equals()似乎没有按预期工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!