简介

当我们需要使用某个对象的属性或方法时,如果该对象为 null,则会抛出空指针异常。为了避免这种异常的发生,我们通常需要在代码中添加大量的 if-else 判断来检查对象是否为 null。这样的代码不仅繁琐,而且不易于阅读和维护。

Optional 类提供了一种更好的方式来处理 null 值。使用 Optional 类,可以将对象的可能存在或不存在的状态封装成一个容器对象,可以避免直接操作对象时出现空指针异常,同时还能让代码更加简洁和易于阅读。

Brian Goetz (Java语言设计架构师)对Optional设计意图的原话如下:

Optional is intended to provide a limited mechanism for library method return types where there needed to be a clear way to represent “no result,” and using null for such was overwhelmingly likely to cause errors.

这句话突出了三个点:

  1. Optional 是用来作为方法返回值的
  2. Optional 是为了清晰地表达返回值中没有结果的可能性
  3. 且如果直接返回 null 很可能导致调用端产生错误(尤其是NullPointerException)

Optional的机制类似于 Java 的受检异常,强迫API调用者面对没有返回值的现实。

因此,不要滥用Optional,关于Optional使用规范可以参考Java 8 Optional 最佳实践

示例

Optional

Optional可能包含或不包含非空值的容器对象。 如果一个值存在,isPresent()将返回true并且get()将返回值。提供依赖于存在或不存在包含值的其他方法,例如orElse(),如果值不存在则返回默认值;ifPresent(),如果值存在则执行代码块。

Optional提供以下方法:

方法类型及返回值 方法名称 描述
static Optional empty() 返回一个空的Optional实例。
boolean equals(Object obj) 指示某个其他对象是否等于此可选项。
Optional filter(Predicate<? super T> predicate) 如果一个值存在,并且该值给定的谓词相匹配时,返回一个 Optional描述的值,否则返回一个空的Optional 。
Optional flatMap(Function<? super T,Optional> mapper) 如果一个值存在,应用提供的Optional映射函数给它,返回该结果,否则返回一个空的Optional 。
T get() 如果Optional中有一个值,返回值,否则抛出 NoSuchElementException 。
int hashCode() 返回当前值的哈希码值(如果有的话),如果没有值,则返回0(零)。
void ifPresent(Consumer<? super T> consumer) 如果存在值,则使用该值调用指定的消费者,否则不执行任何操作。
boolean isPresent() 返回true如果存在值,否则为 false 。
Optional map(Function<? super T,? extends U> mapper) 如果存在一个值,则应用提供的映射函数,如果结果不为空,则返回一个Optional结果的Optional 。
static Optional of(T value) 返回具有Optional的当前非空值的Optional。
static Optional ofNullable(T value) 返回一个Optional指定值的Optional,如果非空,则返回一个空的Optional 。
T orElse(T other) 返回值如果存在,否则返回other 。
T orElseGet(Supplier<? extends T> other) 返回值(如果存在),否则调用other并返回该调用的结果。
T orElseThrow(Supplier<? extends X> exceptionSupplier) 返回包含的值(如果存在),否则抛出由提供的供应商创建的异常。
String toString() 返回此可选的非空字符串表示,适用于调试。

测试方法:

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
private static void test1() {
// 测试empty方法
Optional<User> empty = Optional.<User>empty();
System.out.println("测试empty方法:");
System.out.println(empty);
System.out.println("-----------------------");

// 测试equals方法
Optional<User> optional1 = Optional.of(User.builder().username("lisi").build());
Optional<User> optional2 = Optional.of(User.builder().username("zhangsan").build());
System.out.println("测试equals方法:");
System.out.println(optional1.equals(optional2));
System.out.println("-----------------------");

// 测试filter方法
Optional<User> optional3 = Optional.of(User.builder().username("zhangsan").build());
Optional<User> optional4 = optional3.filter(new Predicate<User>() {
@Override
public boolean test(User user) {
return Objects.equals("zhangsan", user.getUsername());
}
});
System.out.println("测试filter方法:");
System.out.println(optional4);
System.out.println("-----------------------");

// 测试flatMap方法
Optional<User> optional5 = Optional.of(User.builder().username("zhangsan").build());
Optional<User> optional6 = optional5.flatMap(new Function<User, Optional<User>>() {
@Override
public Optional<User> apply(User user) {
if (Objects.equals("zhangsan", user.getUsername())) {
return Optional.of(user);
}
return Optional.empty();
}
});
System.out.println("测试flatMap方法:");
System.out.println(optional6);
System.out.println("-----------------------");

// 测试get方法
Optional<User> optional7 = Optional.of(User.builder().username("zhangsan").build());
System.out.println("测试get方法:");
System.out.println(optional7.get());
System.out.println("-----------------------");

// 测试hashCode方法
Optional<User> optional8 = Optional.of(User.builder().username("zhangsan").build());
System.out.println("测试hashCode方法:");
System.out.println(optional8.hashCode());
System.out.println("-----------------------");

// 测试ifPresent方法
Optional<User> optional9 = Optional.of(User.builder().username("zhangsan").build());
System.out.println("测试ifPresent方法:");
optional9.ifPresent(new Consumer<User>() {
@Override
public void accept(User user) {
System.out.println(user);
}
});
System.out.println("-----------------------");

// 测试isPresent方法
Optional<User> optional10 = Optional.of(User.builder().username("zhangsan").build());
System.out.println("测试isPresent方法:");
System.out.println(optional10.isPresent());
System.out.println("-----------------------");

// 测试map方法
Optional<User> optional11 = Optional.of(User.builder().username("zhangsan").build());
System.out.println("测试map方法:");
Optional<User> optional12 = optional11.map(new Function<User, User>() {
@Override
public User apply(User user) {
if (Objects.equals("zhangsan", user.getUsername())) {
return user;
}
return null;
}
});
System.out.println(optional12);
System.out.println("-----------------------");

// 测试of方法
Optional<User> optional13 = Optional.of(User.builder().username("zhangsan").build());
System.out.println("测试of方法:");
System.out.println(optional13);
System.out.println("-----------------------");

// 测试ofNullable方法
Optional<User> optional14 = Optional.ofNullable(User.builder().username("zhangsan").build());
System.out.println("测试ofNullable方法:");
System.out.println(optional14);
System.out.println("-----------------------");

// 测试orElse方法
Optional<User> optional15 = Optional.empty();
System.out.println("测试orElse方法:");
System.out.println(optional15.orElse(User.builder().username("zhangsan").build()));
System.out.println("-----------------------");

// 测试orElseGet方法
Optional<User> optional16 = Optional.empty();
System.out.println("测试orElse方法:");
System.out.println(optional16.orElseGet(new Supplier<User>() {
@Override
public User get() {
return User.builder().username("zhangsan").build();
}
}));
System.out.println("-----------------------");

// 测试toString方法
System.out.println("测试toString方法:");
Optional<User> optional17 = Optional.of(User.builder().username("zhangsan").build());
String s = optional17.toString();
System.out.println(s);
System.out.println("-----------------------");
}

控制台输出:

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
测试empty方法:
Optional.empty
-----------------------
测试equals方法:
false
-----------------------
测试filter方法:
Optional[User(age=null, height=null, weight=null, username=zhangsan)]
-----------------------
测试flatMap方法:
Optional[User(age=null, height=null, weight=null, username=zhangsan)]
-----------------------
测试get方法:
User(age=null, height=null, weight=null, username=zhangsan)
-----------------------
测试hashCode方法:
-1431681035
-----------------------
测试ifPresent方法:
User(age=null, height=null, weight=null, username=zhangsan)
-----------------------
测试isPresent方法:
true
-----------------------
测试map方法:
Optional[User(age=null, height=null, weight=null, username=zhangsan)]
-----------------------
测试of方法:
Optional[User(age=null, height=null, weight=null, username=zhangsan)]
-----------------------
测试ofNullable方法:
Optional[User(age=null, height=null, weight=null, username=zhangsan)]
-----------------------
测试orElse方法:
User(age=null, height=null, weight=null, username=zhangsan)
-----------------------
测试orElse方法:
User(age=null, height=null, weight=null, username=zhangsan)
-----------------------
测试toString方法:
Optional[User(age=null, height=null, weight=null, username=zhangsan)]
-----------------------

OptionalInt

OptionalInt可能含有也可能不包含int值的容器对象。 如果值存在, isPresent()将返回true并且getAsInt()将返回值。

提供依赖于包含值的存在或不存在的附加方法,例如orElse(),如果值不存在则返回默认值;ifPresent(),如果值存在则执行代码块。

OptionalInt提供以下方法:

方法类型及返回值 方法名称 描述
static OptionalInt empty() 返回一个空的 OptionalInt实例。
boolean equals(Object obj) 指示某个其他对象是否等于此OptionalInt。
int getAsInt() 如果 OptionalInt中存在值,则返回值,否则抛出 NoSuchElementException 。
int hashCode() 返回当前值的哈希码值(如果有的话),如果没有值,则返回0(零)。
void ifPresent(IntConsumer consumer) 让指定的消费者接受该值,如果一个值存在,否则什么也不做。
boolean isPresent() 如果有值存在,返回 true ,否则 false 。
static OptionalInt of(int value) 返回一个 OptionalInt具有指定值存在。
int orElse(int other) 返回值如果存在,否则返回 other 。
int orElseGet(IntSupplier other) 返回值(如果存在),否则调用 other并返回该调用的结果。
int orElseThrow(Supplier exceptionSupplier) 返回包含的值(如果存在),否则抛出由提供的供应商创建的异常。
String toString() 返回对象的字符串表示形式。

测试方法:

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
@SneakyThrows
private static void test2(){
// 测试empty方法
System.out.println("测试empty方法:");
OptionalInt empty = OptionalInt.empty();
System.out.println(empty);
System.out.println("-----------------------");

// 测试equals方法
System.out.println("测试equals方法:");
OptionalInt optionalInt = OptionalInt.of(3);
OptionalInt optionalInt1 = OptionalInt.of(4);
System.out.println(optionalInt.equals(optionalInt1));
System.out.println("-----------------------");

// 测试getAsInt方法
System.out.println("测试getAsInt方法:");
OptionalInt optionalInt2 = OptionalInt.of(1);
System.out.println(optionalInt2.getAsInt());
System.out.println("-----------------------");

// 测试hashCode方法
System.out.println("测试hashCode方法:");
OptionalInt optionalInt3 = OptionalInt.of(1);
System.out.println(optionalInt3.hashCode());
System.out.println("-----------------------");

// 测试ifPresent方法
System.out.println("测试ifPresent方法:");
OptionalInt optionalInt4 = OptionalInt.of(1);
optionalInt4.ifPresent(new IntConsumer() {
@Override
public void accept(int value) {
System.out.println("打印值:" + value);
}
});
System.out.println("-----------------------");

// 测试of方法
System.out.println("测试of方法:");
OptionalInt optionalInt5 = OptionalInt.of(1);
System.out.println(optionalInt5);
System.out.println("-----------------------");

// 测试orElse方法
System.out.println("测试orElse方法:");
OptionalInt optionalInt6 = OptionalInt.of(1);
System.out.println(optionalInt6.orElse(-1));
System.out.println("-----------------------");

// 测试orElseGet方法
System.out.println("测试orElseGet方法:");
OptionalInt optionalInt7 = OptionalInt.of(1);
System.out.println(optionalInt7.orElseGet(new IntSupplier() {
@Override
public int getAsInt() {
return -1;
}
}));
System.out.println("-----------------------");

// 测试orElseGet方法
System.out.println("测试orElseGet方法:");
OptionalInt optionalInt8 = OptionalInt.of(1);
optionalInt8.orElseThrow(new Supplier<Throwable>() {
@Override
public Throwable get() {
return new Throwable("没有值");
}
});
System.out.println("-----------------------");

// 测试toString方法
System.out.println("测试toString方法:");
OptionalInt optionalInt9 = OptionalInt.of(1);
String s = optionalInt9.toString();
System.out.println(s);
System.out.println("-----------------------");
}

控制台输出:

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
测试empty方法:
OptionalInt.empty
-----------------------
测试equals方法:
false
-----------------------
测试getAsInt方法:
1
-----------------------
测试hashCode方法:
1
-----------------------
测试ifPresent方法:
打印值:1
-----------------------
测试of方法:
OptionalInt[1]
-----------------------
测试orElse方法:
1
-----------------------
测试orElseGet方法:
1
-----------------------
测试orElseGet方法:
-----------------------
测试toString方法:
OptionalInt[1]
-----------------------

OptionalLong

OptionalLong可能含有也可能不包含int值的容器对象。 如果值存在, isPresent()将返回true并且getAsLong()将返回值。

提供依赖于包含值的存在或不存在的附加方法,例如orElse(),如果值不存在则返回默认值;ifPresent(),如果值存在则执行代码块。

OptionalLong提供以下方法:

方法类型及返回值 方法名称 描述
static OptionalLong empty() 返回一个空的OptionalLong实例。
boolean equals(Object obj) 指示一些其他对象是否等于此OptionalLong。
long getAsLong() 如果 OptionalLong中存在值,则返回值,否则抛出 NoSuchElementException 。
int hashCode() 返回当前值的哈希码值(如果有的话),如果没有值,则返回0(零)。
void ifPresent(LongConsumer consumer) 让指定的消费者接受该值,如果一个值存在,否则什么也不做。
boolean isPresent() 如果存在值,则返回true ,否则为 false 。
static OptionalLong of(long value) 返回一个OptionalLong具有指定值存在。
long orElse(long other) 返回值如果存在,否则返回other 。
long orElseGet(LongSupplier other) 返回值(如果存在),否则调用other并返回该调用的结果。
long orElseThrow(Supplier exceptionSupplier) 返回包含的值(如果存在),否则抛出由提供的供应商创建的异常。
String toString() 返回对象的字符串表示形式。

测试方法:

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
@SneakyThrows
private static void test3(){
// 测试empty方法
System.out.println("测试empty方法:");
OptionalLong empty = OptionalLong.empty();
System.out.println(empty);
System.out.println("-----------------------");

// 测试equals方法
System.out.println("测试equals方法:");
OptionalLong optionalInt = OptionalLong.of(3);
OptionalLong optionalInt1 = OptionalLong.of(4);
System.out.println(optionalInt.equals(optionalInt1));
System.out.println("-----------------------");

// 测试getAsLong方法
System.out.println("测试getAsLong方法:");
OptionalLong optionalInt2 = OptionalLong.of(1);
System.out.println(optionalInt2.getAsLong());
System.out.println("-----------------------");

// 测试hashCode方法
System.out.println("测试hashCode方法:");
OptionalLong optionalInt3 = OptionalLong.of(1);
System.out.println(optionalInt3.hashCode());
System.out.println("-----------------------");

// 测试ifPresent方法
System.out.println("测试ifPresent方法:");
OptionalLong optionalInt4 = OptionalLong.of(1);
optionalInt4.ifPresent(new LongConsumer() {
@Override
public void accept(long value) {
System.out.println("打印值:" + value);
}
});
System.out.println("-----------------------");

// 测试of方法
System.out.println("测试of方法:");
OptionalLong optionalInt5 = OptionalLong.of(1);
System.out.println(optionalInt5);
System.out.println("-----------------------");

// 测试orElse方法
System.out.println("测试orElse方法:");
OptionalLong optionalInt6 = OptionalLong.of(1);
System.out.println(optionalInt6.orElse(-1));
System.out.println("-----------------------");

// 测试orElseGet方法
System.out.println("测试orElseGet方法:");
OptionalLong optionalInt7 = OptionalLong.of(1);
System.out.println(optionalInt7.orElseGet(new LongSupplier() {
@Override
public long getAsLong() {
return -1;
}
}));
System.out.println("-----------------------");

// 测试orElseGet方法
System.out.println("测试orElseGet方法:");
OptionalLong optionalInt8 = OptionalLong.of(1);
optionalInt8.orElseThrow(new Supplier<Throwable>() {
@Override
public Throwable get() {
return new Throwable("没有值");
}
});
System.out.println("-----------------------");

// 测试toString方法
System.out.println("测试toString方法:");
OptionalLong optionalInt9 = OptionalLong.of(1);
String s = optionalInt9.toString();
System.out.println(s);
System.out.println("-----------------------");
}

控制台输出:

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
测试empty方法:
OptionalLong.empty
-----------------------
测试equals方法:
false
-----------------------
测试getAsLong方法:
1
-----------------------
测试hashCode方法:
1
-----------------------
测试ifPresent方法:
打印值:1
-----------------------
测试of方法:
OptionalLong[1]
-----------------------
测试orElse方法:
1
-----------------------
测试orElseGet方法:
1
-----------------------
测试orElseGet方法:
-----------------------
测试toString方法:
OptionalLong[1]
-----------------------

OptionalDouble

OptionalDouble可能含有也可能不包含int值的容器对象。 如果值存在, isPresent()将返回true并且getAsDouble()将返回值。

提供依赖于包含值的存在或不存在的附加方法,例如orElse(),如果值不存在则返回默认值;ifPresent(),如果值存在则执行代码块。

OptionalDouble提供以下方法:

方法类型及返回值 方法名称 描述
static OptionalDouble empty() 返回一个空的 OptionalDouble实例。
boolean equals(Object obj) 指示某个其他对象是否等于此OptionalDouble。
double getAsDouble() 如果 OptionalDouble中有值,则返回值,否则抛出 NoSuchElementException 。
int hashCode() 返回当前值的哈希码值(如果有的话),如果没有值,则返回0(零)。
void ifPresent(DoubleConsumer consumer) 让指定的消费者接受该值,如果一个值存在,否则什么也不做。
boolean isPresent() 返回 true如果存在值,否则为 false 。
static OptionalDouble of(double value) 返回一个 OptionalDouble具有指定值存在。
double orElse(double other) 返回值如果存在,否则返回 other 。
double orElseGet(DoubleSupplier other) 返回值(如果存在),否则调用 other并返回该调用的结果。
double orElseThrow(Supplier exceptionSupplier) 返回包含的值(如果存在),否则抛出由提供的供应商创建的异常。
String toString() 返回对象的字符串表示形式。

测试方法:

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
@SneakyThrows
private static void test4(){
// 测试empty方法
System.out.println("测试empty方法:");
OptionalDouble empty = OptionalDouble.empty();
System.out.println(empty);
System.out.println("-----------------------");

// 测试equals方法
System.out.println("测试equals方法:");
OptionalDouble optionalInt = OptionalDouble.of(3);
OptionalDouble optionalInt1 = OptionalDouble.of(4);
System.out.println(optionalInt.equals(optionalInt1));
System.out.println("-----------------------");

// 测试getAsDouble方法
System.out.println("测试getAsDouble方法:");
OptionalDouble optionalInt2 = OptionalDouble.of(1);
System.out.println(optionalInt2.getAsDouble());
System.out.println("-----------------------");

// 测试hashCode方法
System.out.println("测试hashCode方法:");
OptionalDouble optionalInt3 = OptionalDouble.of(1);
System.out.println(optionalInt3.hashCode());
System.out.println("-----------------------");

// 测试ifPresent方法
System.out.println("测试ifPresent方法:");
OptionalDouble optionalInt4 = OptionalDouble.of(1);
optionalInt4.ifPresent(new DoubleConsumer() {
@Override
public void accept(double value) {
System.out.println("打印值:" + value);
}
});
System.out.println("-----------------------");

// 测试of方法
System.out.println("测试of方法:");
OptionalDouble optionalInt5 = OptionalDouble.of(1);
System.out.println(optionalInt5);
System.out.println("-----------------------");

// 测试orElse方法
System.out.println("测试orElse方法:");
OptionalDouble optionalInt6 = OptionalDouble.of(1);
System.out.println(optionalInt6.orElse(-1));
System.out.println("-----------------------");

// 测试orElseGet方法
System.out.println("测试orElseGet方法:");
OptionalDouble optionalInt7 = OptionalDouble.of(1);
System.out.println(optionalInt7.orElseGet(new DoubleSupplier() {
@Override
public double getAsDouble() {
return -1;
}
}));
System.out.println("-----------------------");

// 测试orElseGet方法
System.out.println("测试orElseGet方法:");
OptionalDouble optionalInt8 = OptionalDouble.of(1);
optionalInt8.orElseThrow(new Supplier<Throwable>() {
@Override
public Throwable get() {
return new Throwable("没有值");
}
});
System.out.println("-----------------------");

// 测试toString方法
System.out.println("测试toString方法:");
OptionalDouble optionalInt9 = OptionalDouble.of(1);
String s = optionalInt9.toString();
System.out.println(s);
System.out.println("-----------------------");
}

控制台输出:

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
测试empty方法:
OptionalDouble.empty
-----------------------
测试equals方法:
false
-----------------------
测试getAsDouble方法:
1.0
-----------------------
测试hashCode方法:
1072693248
-----------------------
测试ifPresent方法:
打印值:1.0
-----------------------
测试of方法:
OptionalDouble[1.0]
-----------------------
测试orElse方法:
1.0
-----------------------
测试orElseGet方法:
1.0
-----------------------
测试orElseGet方法:
-----------------------
测试toString方法:
OptionalDouble[1.0]
-----------------------