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 什么时候比较 date1
和 date2
比较 date2
和 date1
时,您必须 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;
.
我创建了一个像这样的 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 什么时候比较 date1
和 date2
比较 date2
和 date1
时,您必须 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;
.