Java TreeMap returns 当值存在时键为空

Java TreeMap returns null for key when value exists

我创建了一个像这样的 TreeMap:

   Map<Date, List<MyInput>> inputsByDate = new TreeMap<>(new Comparator<Date>() {
        @Override
        public int compare(Date lhs, Date rhs) {
            return dateUtil.compareDay(lhs, rhs);
        }


    });

我在比较器中的方法不是很漂亮,但至少可以识别相似性(由于其他原因,我没有将 HashMap 与 equals 和 hash 一起使用):

public int compareDay(Date lhs, Date rhs) {
    Calendar cal1 = Calendar.getInstance();
    Calendar cal2 = Calendar.getInstance();
    cal1.setTime(lhs);
    cal2.setTime(rhs);
    boolean sameDay = cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
            cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR);
    if (sameDay) {
        return 0;
    } else {
        return -1;
    }
}

无论如何,问题出在下面的代码片段上。当我检索它时,最后一个元素为空。

public List<MyType> convert(Map<Date, List<MyInput>> inputByDate, Map<Date, Boolean> isDoneByDate) {
        List<MyType> result = Lists.newArrayList();
        for (Date dateKey : inputByDate.keySet()) {
            boolean isDone = false;
            Boolean res = isDoneByDate.get(dateKey);
            if (res != null) {
                isDone = res;
            }
            List<MyInput> inputs = inputByDate.get(dateKey);

            MyType retrieved=new MyType(dateKey, inputs, isDone);
            result.add(retrieved);
        }
        return result;
    }

当我使用调试器 运行 最后一个片段时,我可以清楚地看到(作为示例)有 3 个键的值不为空。我一定在这里遗漏了一些东西,因为如果我之前已经验证每个键都与有效对匹配,我看不到报告如何为空。任何帮助将不胜感激。

如果日期不同,你的比较器应该 return -1 1 因为它必须是对称的,即如果你 return -1 什么时候比较 date1date2 比较 date2date1 时,您必须 return 1。您的代码必然会破坏映射,因为它无法可靠地确定键的顺序。

因此,将您的 compare() 重构为如下内容:

int result = Integer.compare( cal1.get(Calendar.YEAR), cal2.get(Calendar.YEAR));
if( result == 0 ) { //if the year is equal compare the days
  result = Integer.compare( cal1.get(Calendar.DAY_OF_YEAR), cal2.get(Calendar.DAY_OF_YEAR));
}
return result;

编辑:关于你的比较器可能发生的事情的小细节。

如果您查看源代码,您会发现地图会将新密钥与现有密钥进行比较。因此,您的比较器将根据插入顺序对它们进行排序,即由于您总是 return -1 对于不相等的键,映射将始终跟随左分支,因此最后添加的元素将是 "smallest"。不过那只是另一个问题。

您遇到的问题是在 getEntryUsingComparator() 方法中找到的,该方法由 get(key) 间接调用。该方法如下所示:

Comparator<? super K> cpr = comparator;
if (cpr != null) {
  Entry<K,V> p = root;
  while (p != null) {
    int cmp = cpr.compare(k, p.key);
    if (cmp < 0)
      p = p.left;
    else if (cmp > 0)
      p = p.right;
    else
      return p;
  }
}
return null;

如您所见,由于总是 returning -1,该方法将始终执行 cmp < 0 分支,直到 p = p.left 导致 p = null,因为没有更多左元素然后 while 循环终止,你最终在 return null;.