当值存在时,Java TreeMap为键返回null

时间:2016-09-12 15:40:40

标签: java comparator treemap

我已经创建了这样的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;
    }
}

无论如何,问题是下面的代码片段。我检索它时,最后一个元素是null。

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个键的值不为空。我必须在这里遗漏一些东西,因为如果我已经验证每个密钥与之前的有效对匹配,我就看不到报告如何为空。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:3)

如果日期不同,比较器应返回-1 1,因为它必须是对称的,即如果在比较date1date2时返回-1比较date2date1时必须返回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;

编辑:对比较器可能发生的情况进行细分。

如果您查看了来源,您会看到地图会将新密钥与现有密钥进行比较。因此,您的比较器将根据插入顺序对它们进行排序,即,因为对于非相等键,您总是返回-1,因此地图将始终跟随左分支,因此最后添加的元素将是&#34;最小的&#34;。这只是另一个问题。

您遇到的问题可以在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;

正如您所看到的,由于始终返回-1,该方法将始终执行cmp < 0分支,直到p = p.left导致p = null,因为没有剩余的元素,然后是while循环已终止,您最终到达return null;