一、HashMap存储null
HashMap键或者值都可以null,只不过允许一个key为null,多个value为null,key相同覆盖先前的值。
二、那么TreeMap能否存储null值呢?
public static void main(String[] args) {
TreeMap<String, String> map = new TreeMap<>();
map.put("name", "andy");
map.put("age", "17");
//map.put(null, "byx"); // 编译正常、运行报空指针异常
map.put("address", null); // 运行正常
System.out.println(map.get("address"));
}
说明TreeMap的value可以是null,(没有自定义比较器)key不能为null。
三、分析map.put(null, "byx")空指针异常原因
调用栈:put方法-------------------->compare方法
final int compare(Object k1, Object k2) {
return comparator==null ? ((Comparable<? super K>)k1).compareTo((K)k2) : comparator.compare((K)k1, (K)k2);
}
compare中调用了String的compareTo方法,k1为null,可想而知会报空指针异常。
上述异常解决办法:自定义Comparator,重写compare方法
TreeMap<String, String> map = new TreeMap<>(new Comparator<String>() {
public int compare(String s1, String s2) { // s1待存储数据,s2已存储数据
if (s1 == null) {
return 1;
} else {
return s2.charAt(0) - s1.charAt(0); }
}
}
);
map.put("name", "andy");
map.put("age", "17");
map.put(null, "byx"); // 运行正常
System.out.println(map.get(null)); // get获取不到值,返回null
// 但是如下方式遍历可以获取键值对
Set<Map.Entry<String, String>> s = map.entrySet();
for (Map.Entry<String, String> entry : s) {
System.out.println(entry);
}
返回结果如下:
name=andy
age=17
null=byx
四、分析上述map.get(null)返回null原因
调用栈:get方法-------------------->getEntry方法-------------------->getEntryUsingComparator方法(自定义了Comparator 时)
public V get(Object key) {
Entry<K,V> p = getEntry(key);
return (p==null ? null : p.value);
}
final Entry<K,V> getEntry(Object key) {
// Offload comparator-based version for sake of performance
if (comparator != null)
return getEntryUsingComparator(key);
//以下代码省略
}
final Entry<K,V> getEntryUsingComparator(Object key) {
@SuppressWarnings("unchecked")
K k = (K) 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;
}
// 再举个例子,强制改变比较器compare方法返回值
Map<Integer, String> map = new TreeMap<>(new Comparator<Integer>() {
public int compare(Integer i1, Integer i2) {
int num = i1 - i2;
return num == 0 ? 1 : num;
}
}
);
map.put(11, "andy");
map.put(22, "ivan");
map.put(33, "eason");
map.put(11, "edison");
System.out.println(map.get(11)); // 即使key不为null时也会返回null
通过上述源码可知:底层取值使用了自定义比较器的compare方法,TreeMap采用红黑树数据结构存储数据。调用get(key)时,会调用比较器中的compare方法,使用传入的Key逐个比对树中存储节点:<0则往左查找,>0往右查找,只有当=0时才返回该值,而上述调用null是返回1,则一直往右查找,永远找不到最终返回null。
五、TreeSet又能否存储null值呢?
TreeSet底层使用了TreeMap来操作数据, 存储null值同TreeMap的put(null, "XXX")一样会报空指针异常。解决方式同TreeMap一致,自定义Comparator,重写compare方法。
public TreeSet(Comparator<? super E> comparator) {
this(new TreeMap<>(comparator));
}
关于TreeMap存储null问题
最新推荐文章于 2022-12-03 22:39:21 发布