java.util.Date equals()似乎没有按预期工作 [英] java.util.Date equals() doesn't seem to work as expected

查看:125
本文介绍了java.util.Date equals()似乎没有按预期工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 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 effectiveDates 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) 日期#equals doc说明这一点

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)返回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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆