Java 语言里面,Map 类十分常用,它能让我们存放多个 key-value 键值对,甚至有时候会用它代替实体类来使用。

但是 Map 的值是可以为 null 的。

而 null 的存在也会有能导致 NullException,这也是我们非常不愿意看到的情况。

要想避免 NullException,我们一般的做法就是针对值先做非空判断,然后根据结果去选择执行。

那么有没有简单的方法呢?

JDK 1.8 里的 Map 如何防止空指针

在 JDK 1.8 里,我们就可以很简单的防止 Map 里面的某个 value 是 null 可能导致 NullException 的问题了。

它就是 getOrDefault 方法:

  1. default V getOrDefault(Object key, V defaultValue) {
  2. V v;
  3. return (((v = get(key)) != null) || containsKey(key))
  4. ? v
  5. : defaultValue;
  6. }

可以看到,这个方法需要两个参数,一个是 key,一个是 defaultValue。

前一个很好理解,就是键值对的键,跟 Map 里面的 get 方法参数一样;后一个就是当 key 对应的 value 不存在或者为 null 时,返回的默认值。

其实很简单,就相当于三目运算符的变种,当 key 对应的 value 值为 null 的时候,设置一个默认值。

JDK 1.8 Map 里的 computeIfAbsent

有时候我们会在一个 Map 里面存放下面这样的格式:

  1. Map<String, List<String>> map = new HashMap();
  2. List<String> books = map.get("books");
  3. if (Objects.isNull(books)) {
  4. books = new ArrayList<>();
  5. }
  6. System.out.println(books);

可以看到,我们想对 Map 里某个集合类型 key 赋值的时候,为了防止 value 对象是 null 的时候,需要加额外的判断条件。

如果 key 对应的集合对象不存在,需要主动创建一个再 put 到 Map 对象里面。

虽然逻辑上没啥问题,但是程序的代码行数看着是挺繁琐的。

这时候我们就可以使用 computeIfAbsent 方法来解决这个问题了。

  1. default V computeIfAbsent(K key,
  2. Function<? super K, ? extends V> mappingFunction) {
  3. Objects.requireNonNull(mappingFunction);
  4. V v;
  5. if ((v = get(key)) == null) {
  6. V newValue;
  7. if ((newValue = mappingFunction.apply(key)) != null) {
  8. put(key, newValue);
  9. return newValue;
  10. }
  11. }
  12. return v;
  13. }

这个方法同样需要两个参数,一个是 key;另一个是一个函数表达式。

作用是如果 Map 中 key 对应的 value 不存在,则会将函数表达式产生的值作为作为该 key 的 value,并且返回该值;如果 key 对应的 value 存在,就直接返回该 key 对应的 value。

我们使用这个方法来重新实现下上面的程序。

  1. Map<String, List<String>> map = new HashMap();
  2. List<String> books = map.computeIfAbsent("books", key -> new ArrayList<>());
  3. System.out.println(books);

怎么样,是不是代码更加简洁了。