开发中遇到的Map的get空指针问题
0、前置
什么是Map.of()?
/**
* Returns an unmodifiable map containing zero mappings.
* See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
*
* @param <K> the {@code Map}'s key type
* @param <V> the {@code Map}'s value type
* @return an empty {@code Map}
*
* @since 9
*/
@SuppressWarnings("unchecked")
static <K, V> Map<K, V> of() {
return (Map<K,V>) ImmutableCollections.EMPTY_MAP;
}
Map.of() 是 Java 9 中引入的一种方法,它允许开发人员创建最多包含 10 个键值对的不可变映射。
它提供了一种方便简洁的 Map 创建方式,无需编写大量代码即可轻松创建小型Map。Map.of()是对以前使用类的构造函数创建小Map的方法的改进HashMap,这种方法可能很麻烦且冗长。
什么是HashMap?
/**
* Constructs an empty {@code HashMap} with the specified initial
* capacity and the default load factor (0.75).
*
* @param initialCapacity the initial capacity.
* @throws IllegalArgumentException if the initial capacity is negative.
*/
public HashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
/**
* Constructs an empty {@code HashMap} with the default initial capacity
* (16) and the default load factor (0.75).
*/
public HashMap() {
this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
new HashMap<>() 是Java中类提供的构造函数HashMap,允许开发者新建一个HashMap. 它用于创建可变映射,这意味着可以通过添加、删除或更新键值对来修改映射。
它是在 Java 中创建Map的常用方法,尤其是在处理较大的数据集时。
1、Map获取value的方法
map.get(key) 和 map.getOrDefault(key, defaultValue)
两个Map都可以使用 get 或者 getOrDefault 方法获取map中的key对应的value
BUT !!!
我们现在做一个测试
public static void main(String[] args) {
Map<Object, Object> hashMap = new HashMap<>();
Map<Object, Object> mapOf = Map.of();
Object mapObject = hashMap.get("");
Object mapOfObject = mapOf.get("");
System.out.println(map);
System.out.println(mapOfObject);
}
输出结果:
这样输出的结果是正确的,因为两个map都是空的所以返回的结果是null
然而,是这样的吗?不妨我们想一想,get中的key可能是不同的类型的,然后我们把key换一下试试!
@Data
static class TestA {
private Long id;
private String name;
}
public static void main(String[] args) {
Map<Object, Object> hashMap = new HashMap<>();
Map<Object, Object> mapOf = Map.of();
TestA testA = new TestA();
Object mapTestA = hashMap.get(testA.getId());
Object mapOfTestA = mapOf.get(testA.getId());
System.out.println(mapTestA);
System.out.println(mapOfTestA);
}
输出结果却是这样的:
为什么呢,都是get为什么会导致空指针呢?
2、原因分析
HashMap重写父类get的方法
public V get(Object key) {
Node<K,V> e;
return (e = getNode(key)) == null ? null : e.value;
}
而 Map.of()重写的get方法是
@Override
@SuppressWarnings("unchecked")
public V get(Object o) {
if (size == 0) {
Objects.requireNonNull(o);
return null;
}
int i = probe(o);
if (i >= 0) {
return (V)table[i+1];
} else {
return null;
}
}
我们在回归回来看一下,当时我们用对象的属性字段去获取Map中的value的时候,对象中的属性值可能是个null值
最后通过map去get的时候就会出现Map.of()使用get方法的时候就会走到 Objects.requireNonNull(o); 这一行,最终导致空指针异常!
3、总结
Map.of()在 Java 中使用有几个好处:
Map.of()提供了一种在 Java 中创建Map的简洁方便的方法。这使得代码更具可读性和更易于维护。
Map.of()创建不可变映射,这意味着映射一旦创建,就无法修改。这为Map中存储的数据提供了一定程度的安全性和保障性。
Map.of()为映射的键和值提供类型安全,这有助于防止使用 new 时可能发生的类型相关错误的HashMap<>()。
4、写在最后
报错主要是因为Map.of()不允许键或值为null。
Map.of() 内部实现会检査传入的所有键和值,如果发现任何一个键或值是null,它会立即抛出 NullPointerException。
这是因为不可变映射的设计原则之一就是保证映射的完整性和安全性,避免潜在的 null 值引发的问题。
5、最后的最后
在组装一些零散的map数据的时候Map.of还是很好用的,最后祝大家UpUpUp,每天多学一点,好记性不如烂笔头嘛!