序
Java 语言里面,Map 类十分常用,它能让我们存放多个 key-value 键值对,甚至有时候会用它代替实体类来使用。
但是 Map 的值是可以为 null 的。
而 null 的存在也会有能导致 NullException,这也是我们非常不愿意看到的情况。
要想避免 NullException,我们一般的做法就是针对值先做非空判断,然后根据结果去选择执行。
JDK 1.8 里的 Map 如何防止空指针
在 JDK 1.8 里,我们就可以很简单的防止 Map 里面的某个 value 是 null 可能导致 NullException 的问题了。
它就是 getOrDefault
方法:
default V getOrDefault(Object key, V defaultValue) {
V v;
return (((v = get(key)) != null) || containsKey(key))
? v
: defaultValue;
}
可以看到,这个方法需要两个参数,一个是 key,一个是 defaultValue。
前一个很好理解,就是键值对的键,跟 Map 里面的 get 方法参数一样;后一个就是当 key 对应的 value 不存在或者为 null 时,返回的默认值。
其实很简单,就相当于三目运算符的变种,当 key 对应的 value 值为 null 的时候,设置一个默认值。
JDK 1.8 Map 里的 computeIfAbsent
有时候我们会在一个 Map 里面存放下面这样的格式:
Map<String, List<String>> map = new HashMap();
List<String> books = map.get("books");
if (Objects.isNull(books)) {
books = new ArrayList<>();
}
System.out.println(books);
可以看到,我们想对 Map 里某个集合类型 key 赋值的时候,为了防止 value 对象是 null 的时候,需要加额外的判断条件。
如果 key 对应的集合对象不存在,需要主动创建一个再 put 到 Map 对象里面。
虽然逻辑上没啥问题,但是程序的代码行数看着是挺繁琐的。
这时候我们就可以使用 computeIfAbsent
方法来解决这个问题了。
default V computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
Objects.requireNonNull(mappingFunction);
V v;
if ((v = get(key)) == null) {
V newValue;
if ((newValue = mappingFunction.apply(key)) != null) {
put(key, newValue);
return newValue;
}
}
return v;
}
这个方法同样需要两个参数,一个是 key;另一个是一个函数表达式。
作用是如果 Map 中 key 对应的 value 不存在,则会将函数表达式产生的值作为作为该 key 的 value,并且返回该值;如果 key 对应的 value 存在,就直接返回该 key 对应的 value。
我们使用这个方法来重新实现下上面的程序。
Map<String, List<String>> map = new HashMap();
List<String> books = map.computeIfAbsent("books", key -> new ArrayList<>());
System.out.println(books);
怎么样,是不是代码更加简洁了。