Java中如何优雅对null值进行处理

一、空指针

NPE(NullPointerException)一直是让java程序员头疼的问题,稍微不注意被调用就会让功能无法使用。所以项目里面很多地方都需要对对象进行非空判断。

二、非空处理

那么我们通常是怎样的判空的呢?

1
2
3
4
5
if (obj == null) {
// do something
} else {
// do something
}

这段代码是不是很常见?如果obj为null,那么就执行一段逻辑,否则执行另外一段逻辑。

由于这样的逻辑会占用很多代码行,也会让代码看起来变得臃肿,所以java官方在java8中优化了相关的链式处理,比如java8中的stream流,而在这里,也有对应的Optional类来处理判空问题。

首先来解读一下Optional类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package java.util;

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

public final class Optional<T> {
// 空的Optional对象
private static final Optional<?> EMPTY = new Optional<>();

// 如果非空,就是value值,如果为空,就没有值
private final T value;

// 无参构造,将value初始化为null
private Optional() {
this.value = null;
}

// 获取一个Optional对象,value为null
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}

// 使用构造器生成一个Optional对象,如果value值为null,就抛出空指针异常
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}

// 使用静态方法获取一个Optional对象,如果value值为null,就抛出空指针异常
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}

// 如果value为null,返回value为null的Optional对象,否则生成一个value为传入value的对象
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}

// 获取当前Optional对象的value值,如果value为null,则抛出异常
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}

// 判断当前Optional对象value值是否非空,不为null则返回true
public boolean isPresent() {
return value != null;
}

// 对当前Optional对象的value值进行操作
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
// 使用consumer消费者方法
consumer.accept(value);
// 否则不做任何操作
}

// 根据条件过滤Optional对象
public Optional<T> filter(Predicate<? super T> predicate) {
// 如果predicate比较方法为null,则抛出空指针异常
Objects.requireNonNull(predicate);
// 如果value值为空,则返回当前Optional对象
if (!isPresent())
return this;
else
// 如果value有值
// 则使用predicate进行比较,如果匹配则返回当前Optional对象
// 不匹配则返回一个value为null的Optional对象
return predicate.test(value) ? this : empty();
}

// 将当前Optional对象的value根据mapper函数封装成另外的Optional对象
// mapper函数入参的类型为value类型的超类型,返回类型为U类型的子类型
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
// 如果mapper函数为null,则抛出空指针异常
Objects.requireNonNull(mapper);
// 如果value值为空,则返回value为null的Optional对象
if (!isPresent())
return empty();
else {
// 如果value有值
// 将mapper.apply(value)的返回值等装成一个Optional对象
return Optional.ofNullable(mapper.apply(value));
}
}

// 将当前Optional对象的value根据mapper函数封装成另外的Optional对象
// mapper函数入参的类型为value类型的超类型,返回类型为value为U类型的Optional对象
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
// 如果mapper函数为null,则抛出空指针异常
Objects.requireNonNull(mapper);
// 如果value值为空,则返回value为null的Optional对象
if (!isPresent())
return empty();
else {
// 如果value有值
// 如果mapper.apply(value)为null,则抛出空指针异常
// 返回mapper.apply(value)
return Objects.requireNonNull(mapper.apply(value));
}
}

// 如果value不为空则返回value,否则返回other
public T orElse(T other) {
return value != null ? value : other;
}

// 如果value不为空则返回value,否则返回other.get()
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}

// 如果value不为空则返回value,否则抛出exceptionSupplier.get()定义的异常
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}

// 比较当前Optional对象与obj是否相等
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}

if (!(obj instanceof Optional)) {
return false;
}

Optional<?> other = (Optional<?>) obj;
return Objects.equals(value, other.value);
}

// 获取当前value的hashcode
@Override
public int hashCode() {
return Objects.hashCode(value);
}

// toString
@Override
public String toString() {
return value != null
? String.format("Optional[%s]", value)
: "Optional.empty";
}
}

通过解读源代码,相信大家对Optional类有了一定的了解了吧!

那么我们来举几个实例,加深一下印象。

新建一个User实体,来进行测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.yl.test;

/**
* 用户实体
*
* @author hanguilin
* @date 2020年7月16日 下午1:32:36
* @version 1.0
*
*/
public class User {

/**
* 姓名
*/
private String name;

/**
* 年龄
*/
private Integer age;

public User() {
super();
}

public User(String name, Integer age) {
super();
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public Integer getAge() {
return age;
}

public void setAge(Integer age) {
this.age = age;
}

}

  1. 如果user实例不为空,则打印年龄
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.yl.test;

import java.util.Optional;

public class TestMain {

public static void main(String[] args) {
User user = null;
Optional<User> userOptional = Optional.ofNullable(user);
userOptional.ifPresent(o -> System.out.println(o.getAge()));
}
}

此时控制台没有任何输出。

我们来测试一下user有值的情况:

1
User user = new User("han", 20);

此时:

如果想将链式写法运用足,那么上面就可以缩写成:

1
Optional.ofNullable(user).ifPresent(o -> System.out.println(o.getAge()));
  1. 如果user实例不为空,则获取年龄,如果为空,新建一个实例,并获取年龄,此时获取的年龄为null
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.yl.test;

import java.util.Optional;

public class TestMain {

public static void main(String[] args) {
User user = new User("han", 20);
Integer age = Optional.ofNullable(user).orElse(new User()).getAge();
System.out.println(age);
}
}

  1. 如果user实例不为空,则获取年龄,如果为空,返回年龄为0
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.yl.test;

import java.util.Optional;

public class TestMain {

public static void main(String[] args) {
User user = null;
Optional<Integer> map = Optional.ofNullable(user).map(User::getAge);
Integer age = map.orElse(0);
System.out.println(age);
}
}
  1. 判断对象是否有值
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.yl.test;

import java.util.Optional;

public class TestMain {

public static void main(String[] args) {
User user = null;
boolean present = Optional.ofNullable(user).isPresent();
System.out.println(present);
}
}

查看评论