我有一个Map<Date, Foo>,以及一个带有effectiveDate属性的数据库对象列表,我想检查一下Date我的地图中的键是否effectiveDate与数据库中的任何一个相同- 如果是这样的话,那么就做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
}
Run Code Online (Sandbox Code Playgroud)
然而,dateMap.containsKey即使我确定它有时存在,但是调用总是返回false.
作为一个完整性检查,我打印出了日期的长值,以及equals()通话和compareTo()通话的结果:
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));
}
Run Code Online (Sandbox Code Playgroud)
结果:
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
Run Code Online (Sandbox Code Playgroud)
1)不应该equals和compareTo同意?(我假设实施java.util.Date至少应该尝试遵循建议java.lang.Comparable).
因此,当且仅当getTime方法为两者返回相同的long值时,两个Date对象才相等.
...看起来该getTime方法为这两个日期返回相同的long值,但equal返回false.任何想法为什么会这样?我搜索过高低,但我没有发现任何人描述同样的问题.
PS我被困了java.util.Date.请不要只推荐JodaTime.
PPS我意识到我可以改变这段代码的结构,并可能让它运行起来.但这应该有效,我不想只是解决它,除非它是一个已知的问题或什么的.这似乎不对.
eth*_*tad 11
正如Mureinik暗示和Sotirios Delimanolis更具体地指出的那样,问题在于实施java.util.Date.
java.util.Date在java.sql包中扩展了3个类,所有这些类似乎都做类似的事情,并且它们在java中的区别并不清楚(似乎它们存在的原因只是使java类更准确地与SQL数据类型对齐) -有关它们差异的更多信息,请查看这个非常详细的答案.
现在,在一个看似严重的设计缺陷中,有人决定使用equals()不对称java.sql.Timestamp - 也就是说,timestamp.equals(date)即使date.equals(timestamp)返回true 也可以返回false .很好的主意.
我写了几行来看看哪些java.sql课程展示了这个荒谬的财产 - 显然它只是Timestamp.这段代码:
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));
Run Code Online (Sandbox Code Playgroud)
收益率:
sqlDate equals utilDate: true
utilDate equals sqlDate: true
time equals utilDate: true
utilDate equals time: true
timestamp equals utilDate: false
utilDate equals timestamp: true
Run Code Online (Sandbox Code Playgroud)
由于java.util.HashMap使用parameter.equals(key)在它的实现containsKey()(而不是key.equals(parameter)),这一个奇怪的结果,在给定的情况出现.
那么,如何解决这个问题呢?
1)Long在地图中使用一个键而不是Date(如Mureinik所说) - 因为java.util.Date并java.util.Timestamp返回相同的值getTime(),所以你使用的是哪个实现无关紧要,键也一样.这种方式看似最简单.
2)在地图中使用之前标准化日期对象.这种方式需要更多的工作,但对我来说似乎更令人满意,因为它更清楚的是地图是什么 - 一堆Foo每一个都存储在一个时刻.这是我最终使用的方式,使用以下方法:
public Date getStandardizedDate(Date date) {
return new Date(date.getTime());
}
Run Code Online (Sandbox Code Playgroud)
它需要一个额外的方法调用(并且在那种情况下是一种荒谬的方法),但对我而言,涉及该代码的代码的可读性增加Map<Date, Foo>是值得的.
| 归档时间: |
|
| 查看次数: |
14118 次 |
| 最近记录: |