Optional的使用详解
1、Optional介绍
- Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。
- Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。
- Optional 类的引入很好的解决空指针异常。
2、构建Optional
构建一个Optional对象;方法有:empty( )、of( )、ofNullable( )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
//返回一个描述给定值的Optional ,如果不为null ,则返回一个空的Optional 。
//参数:值–描述的可能为null值
//类型参数:<T> –值的类型
//返回值:一个Optional与如果指定值是非当前值null ,否则一个空Optional
Optional.ofNullable(
""
);
//返回一个Optional描述给定的非null值。
//参数:value –要描述的值,必须为非null
//类型参数:<T> –值的类型
//返回值:存在值的Optional
Optional.of(
""
);
//返回一个空的Optional实例。 此Optional没有值。
//类型参数:<T> –不存在的值的类型
//返回值:一个空的Optional
//api注意:尽管这样做可能很诱人,但应通过将==与Optional.empty()返回的实例进行比较来避免测试对象是否为空。
// 不能保证它是一个单例。
// 而是使用isPresent()
Optional.empty();
|
3、Optional API 及源码注解
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
|
package
java.util;
import
java.util.function.Consumer;
import
java.util.function.Function;
import
java.util.function.Predicate;
import
java.util.function.Supplier;
import
java.util.stream.Stream;
/**
一个可能包含也可能不包含非null值的容器对象。 如果存在值,则isPresent()返回true 。 如果不存在任何值,则该对象被视为空,并且isPresent()返回false 。
提供了其他取决于所包含值是否存在的方法,例如orElse() (如果不存在值,则返回默认值)和ifPresent() (如果存在值,则执行操作)。
这是一个基于值的类; 在Optional实例上使用标识敏感的操作(包括引用等于( == ),标识哈希码或同步)可能会产生不可预测的结果,应避免使用
*/
public
final
class
Optional<T> {
/**
* empty()通用实例
*/
private
static
final
Optional<?> EMPTY =
new
Optional<>();
/**
* 如果不为空,则为该值;否则为false。 如果为null,则表示不存在任何值
*/
private
final
T value;
/**
构造一个空实例。
impl注意:
通常,每个VM仅应存在一个空实例EMPTY
*/
private
Optional() {
this
.value =
null
;
}
/**
返回一个空的Optional实例。 此Optional没有值。
类型参数:<T> –不存在的值的类型
返回值:一个空的Optional
api注意:
尽管这样做可能很诱人,但应通过将==与Optional.empty()返回的实例进行比较来避免测试对象是否为空。 不能保证它是一个单例。 而是使用isPresent()
*/
public
static
<T> Optional<T> empty() {
@SuppressWarnings
(
"unchecked"
)
Optional<T> t = (Optional<T>) EMPTY;
return
t;
}
/**
使用描述的值构造一个实例。
参数:值–要描述的非null值
抛出:NullPointerException如果值为null
*/
private
Optional(T value) {
this
.value = Objects.requireNonNull(value);
}
/**
返回一个Optional描述给定的非null值。
参数:value –要描述的值,必须为非null
类型参数:<T> –值的类型
返回值:存在值的Optiona
*/
public
static
<T> Optional<T> of(T value) {
return
new
Optional<>(value);
}
/**
返回一个描述给定值的Optional ,如果不为null ,则返回一个空的Optional 。
参数:值–描述的可能为null值
类型参数:<T> –值的类型
返回值:一个Optional与如果指定值是非当前值null ,否则一个空Optional
*/
public
static
<T> Optional<T> ofNullable(T value) {
return
value ==
null
? empty() : of(value);
}
/**
如果存在值,则返回该值,否则抛出NoSuchElementException 。
返回值:此Optional描述的非null值
抛出:NoSuchElementException如果不存在任何值
api注意:此方法的首选替代方法是orElseThrow() 。
*/
public
T get() {
if
(value ==
null
) {
throw
new
NoSuchElementException(
"No value present"
);
}
return
value;
}
/**
如果存在值,则返回true ,否则返回false 。
返回值:如果存在值,则为true ,否则为false
*/
public
boolean
isPresent() {
return
value !=
null
;
}
/**
如果不存在值,则返回true ,否则返回false 。
返回值:如果不存在值,则为true ,否则为false
*/
public
boolean
isEmpty() {
return
value ==
null
;
}
/**
如果存在值,则使用该值执行给定的操作,否则不执行任何操作。
参数:动作–要执行的动作(如果存在值)
*/
public
void
ifPresent(Consumer<?
super
T> action) {
if
(value !=
null
) {
action.accept(value);
}
}
/**
如果存在值,则使用该值执行给定的操作,否则执行给定的基于空的操作。
参数:动作–要执行的动作(如果存在值)emptyAction –要执行的基于空的操作(如果不存在任何值)
抛出:NullPointerException如果存在一个值并且给定的操作为null ,或者不存在任何值并且给定的基于空的操作为null
@since 9
*/
public
void
ifPresentOrElse(Consumer<?
super
T> action, Runnable emptyAction) {
if
(value !=
null
) {
action.accept(value);
}
else
{
emptyAction.run();
}
}
/**
如果存在一个值,并且该值与给定的谓词匹配,则返回描述该值的Optional ,否则返回一个空的Optional 。
参数:谓词–应用于值的谓词(如果存在)
返回值:一个Optional描述此的值Optional ,如果一个值存在并且该值给定的谓词相匹配,否则一个空Optional
抛出:NullPointerException如果谓词为null
*/
public
Optional<T> filter(Predicate<?
super
T> predicate) {
Objects.requireNonNull(predicate);
if
(!isPresent()) {
return
this
;
}
else
{
return
predicate.test(value) ?
this
: empty();
}
}
/**
如果存在值,则返回一个Optional描述(就像by ofNullable ),将给定映射函数应用于该值的结果,否则返回一个空的Optional 。
如果映射函数返回null结果,则此方法返回空的Optional
*/
public
<U> Optional<U> map(Function<?
super
T, ?
extends
U> mapper) {
Objects.requireNonNull(mapper);
if
(!isPresent()) {
return
empty();
}
else
{
return
Optional.ofNullable(mapper.apply(value));
}
}
/**
如果存在一个值,则返回将给定Optional -bearing映射函数应用于该值的结果,否则返回一个空的Optional 。
此方法类似于map(Function) ,但是映射函数是其结果已经是Optional函数,如果调用该函数,则flatMap不会将其包装在其他Optional 。
参数:mapper –应用于值的映射函数(如果存在)
类型参数:<U> –映射函数返回的Optional值的类型
返回值:施加的结果Optional荷瘤映射函数此的值Optional ,如果一个值存在,否则一个空Optional
抛出:NullPointerException如果映射函数为null或返回null结果
*/
public
<U> Optional<U> flatMap(Function<?
super
T, ?
extends
Optional<?
extends
U>> mapper) {
Objects.requireNonNull(mapper);
if
(!isPresent()) {
return
empty();
}
else
{
@SuppressWarnings
(
"unchecked"
)
Optional<U> r = (Optional<U>) mapper.apply(value);
return
Objects.requireNonNull(r);
}
}
/**
如果值存在时,返回一个Optional描述的值,否则将返回一个Optional产生通过供给功能。
参数:供应商–产生要返回的Optional的供应功能
返回值:返回一个Optional描述此的值Optional ,如果一个值存在,否则Optional所生产的供应功能。
抛出:NullPointerException如果提供的函数为null或产生null结果
* @since 9
*/
public
Optional<T> or(Supplier<?
extends
Optional<?
extends
T>> supplier) {
Objects.requireNonNull(supplier);
if
(isPresent()) {
return
this
;
}
else
{
@SuppressWarnings
(
"unchecked"
)
Optional<T> r = (Optional<T>) supplier.get();
return
Objects.requireNonNull(r);
}
}
/**
如果存在值,则返回仅包含该值的顺序Stream ,否则返回空Stream 。
返回值:作为Stream的可选值
* @since 9
*/
public
Stream<T> stream() {
if
(!isPresent()) {
return
Stream.empty();
}
else
{
return
Stream.of(value);
}
}
/**
如果存在值,则返回该值,否则返回other 。
参数:其他–要返回的值(如果不存在任何值)。 可以为null 。
返回值:值(如果存在),否则other
*/
public
T orElse(T other) {
return
value !=
null
? value : other;
}
/**
如果存在值,则返回该值,否则返回由供应函数产生的结果。
参数:供应商–产生要返回的值的供应函数
返回值:值(如果存在),否则提供功能产生的结果
*/
public
T orElseGet(Supplier<?
extends
T> supplier) {
return
value !=
null
? value : supplier.get();
}
/**
* If a value is present, returns the value, otherwise throws
* {@code NoSuchElementException}.
*
* @return the non-{@code null} value described by this {@code Optional}
* @throws NoSuchElementException if no value is present
* @since 10
*/
public
T orElseThrow() {
if
(value ==
null
) {
throw
new
NoSuchElementException(
"No value present"
);
}
return
value;
}
/**
如果存在值,则返回该值,否则抛出由异常提供函数产生的异常。
参数:exceptionSupplier –产生要抛出的异常的提供函数
类型参数:<X> –引发的异常类型
返回值:值(如果存在)
抛出:X –如果不存在任何值NullPointerException如果不存在任何值并且异常提供函数为null
api注意:带有空参数列表的对异常构造函数的方法引用可用作提供者
*/
public
<X
extends
Throwable> T orElseThrow(Supplier<?
extends
X> exceptionSupplier)
throws
X {
if
(value !=
null
) {
return
value;
}
else
{
throw
exceptionSupplier.get();
}
}
}
|
4、测试使用
4.1、构建
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
//返回一个描述给定值的Optional ,如果不为null ,则返回一个空的Optional 。
//参数:值–描述的可能为null值
//类型参数:<T> –值的类型
//返回值:一个Optional与如果指定值是非当前值null ,否则一个空Optional
Optional s1 = Optional.ofNullable(
null
);
// 构建一个value不可以为null的optional对象,如果of()的入参为null会报空指针异常;
Optional<MyUser> s2 = Optional.of(
new
MyUser(
"阿辉2"
,
"123456"
));
// 构建一个value可以为null的optional对象;
Optional<MyUser> s3 = Optional.ofNullable(
null
);
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
/* 输出
* Optional.empty
* Optional[MyUser{id='阿辉2', username='123456'}]
* Optional.empty
**/
|
4.2、判断类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
Optional<MyUser> myUser1 = Optional.empty();
Optional<MyUser> myUser2 = Optional.of(
new
MyUser(
"阿飞"
,
"123456"
));
// filter传入一个lambda,lambda返回值为boolean;true:不做任何改变,false:返回一个空的optional;
Optional<MyUser> myUser3 = myUser2.filter(user ->
"错误的密码"
.equals(user.getUsername()));
// isPresent就是判断value是不是null;我们在调用get之前,一定要先调用isPresent,因为直接如果value是null,直接调用get会报异常;
if
(myUser1.isPresent()) {
MyUser value = myUser1.get();
System.out.println(
"optional value:"
+ value);
}
else
{
System.out.println(
"optional value==null"
);
}
// ifPresent传入一段lambda,当value!=null时,执行里面的逻辑;当当value==null时,啥都不干;
myUser2.ifPresent(value -> System.out.println(
"optional value:"
+ value));
System.out.println(myUser3);
// 输入如下:
//optional value==null
//optional value:MyUser{id='阿飞', username='123456'}
//Optional.empty
|
4.3、获取类(常用)
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
|
Optional<MyUser> userInfoEmptyOpt = Optional.empty();
Optional<MyUser> userInfoOpt = Optional.of(
new
MyUser(
"阿飞"
,
"123456"
));
// 1、直接获取,注意如果value==null,会报NoSuchElementException异常
MyUser userInfo1 = userInfoOpt.get();
// 2、orElse可以传入一个UserInfo类型的对象作为默认值;
// 当value!=null时,返回value值;当value==null时,返回默认值作为代替;
MyUser userInfo2 = userInfoEmptyOpt.orElse(
new
MyUser(
"阿飞1"
,
"123456"
));
// 3、orElseGet和orElse不同的是orElseGet可以传入一段lambda表达式;
// 当value!=null时,返回value值;
// 当value==null时,使用该lambda返回的对象作为默认值;
MyUser userInfo3 = userInfoEmptyOpt.orElseGet(() ->
new
MyUser(
"阿飞2"
,
"123456"
));
// 4、orElseThrow可以传入一段lambda表达式,lambda返回一个Exception;当value!=null时,返回value值;当value==null时,抛出该异常;
MyUser userInfo4 = userInfoOpt.orElseThrow(NullPointerException::
new
);
System.out.println(userInfo1);
System.out.println(userInfo2);
System.out.println(userInfo3);
System.out.println(userInfo4);
// 输出如下:
// UserInfo(username=阿飞, password=123456)
// UserInfo(username=阿飞1, password=123456)
// UserInfo(username=阿飞2, password=123456)
// UserInfo(username=阿飞, password=123456)
|
4.4、转换类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
Optional<MyUser> userInfoOpt = Optional.of(
new
MyUser(
"阿飞"
,
"123456"
));
// 原来value的类型是UserInfo,经过map转换为Optional<String>
Optional<String> username = userInfoOpt.map(MyUser::getId);
// 当map的入参也是一个Optional时,经过map转化后会形成Optional<Optional<String>>这种嵌套结构;但flatMap可以把这种嵌套结构打平;
Optional<Optional<String>> unFlatMap = userInfoOpt.map(user -> Optional.of(user.getId()));
Optional<String> flatMap = userInfoOpt.flatMap(user -> Optional.of(user.getId()));
System.out.println(username);
System.out.println(unFlatMap);
System.out.println(flatMap);
// 输出如下:
// Optional[阿飞]
// Optional[Optional[阿飞]]
// Optional[阿飞]
|
4.5、测试API使用
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
|
import
lombok.AllArgsConstructor;
import
lombok.Data;
import
lombok.NoArgsConstructor;
import
lombok.ToString;
import
org.junit.Test;
import
java.math.BigDecimal;
import
java.util.Optional;
/**
* @version 1.0
* @author: crush
* @date: 2021-04-12 20:51
*/
public
class
OptionalStudy {
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
static
class
Employee {
private
Long id;
private
String name;
private
Boolean leader;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
static
class
Leader {
private
Long employeeId;
private
BigDecimal bonus;
}
/**
* 找到ID为1的员工,如果有奖金就打印出来,没有就打印没有奖金;
* @throws
*/
@Test
public
void
tst() {
Optional<Leader> leader = Optional.ofNullable(getEmployeeById(1L)
.filter(Employee::getLeader)
.map(Employee::getId)
.flatMap(
this
::getLeaderByEmployeeId)
.orElse(
null
));
if
(leader.isPresent()) {
Optional.of(leader.map(Leader::getBonus).map(bonus -> String.format(
"员工ID为1的leader奖金为:%s"
, bonus)).orElse(
"员工ID为1的leader也没有奖金"
)).ifPresent(System.out::println);
}
else
{
System.out.println(
"员工ID为1的leader未找到,他可能只是一个基层员工,不配拥有奖金"
);
}
}
private
Optional<Employee> getEmployeeById(Long id) {
//return Optional.of(new Employee(1L, "大老板", Boolean.TRUE));
return
Optional.of(
new
Employee(1L,
"大老板"
, Boolean.FALSE));
}
private
Optional<Leader> getLeaderByEmployeeId(Long employeeId) {
//return employeeId == 1L ? Optional.of(new Leader(1L, BigDecimal.valueOf(1000000000))) : Optional.empty();
return
employeeId == 1L ? Optional.of(
new
Leader(1L,
null
)) : Optional.empty();
}
}
|
平时:
项目里的实例:
1
2
|
return
Optional.ofNullable(iNewsMapper.selectNewsWithNewsCategoryById(id))
.orElseThrow(() ->
new
BaseException(DataSourceResponseEnum.SELECT_ERROR));
|
ofNullable:
返回一个描述给定值的Optional ,如果不为null ,则返回一个空的Optional 。
orElseThrow
如果存在值,则返回该值,否则抛出由异常提供函数产生的异常。
以前的写法是:
1
2
3
4
5
6
|
if
(iNewsMapper.selectNewsWithNewsCategoryById(id)==
null
){
throw
new
BaseException(DataSourceResponseEnum.SELECT_ERROR);
}
else
{
return
iNewsMapper.selectNewsWithNewsCategoryById(id);
}
|
这种写法是比较丑陋的,为了避免上述丑陋的写法,让丑陋的设计变得优雅。JAVA8提供了Optional类来优化这种写法。
例二:
1
2
3
4
5
6
7
8
|
Optional<News> news = Optional.ofNullable(iNewsMapper.selectNewsWithNewsCategoryById(id));
news.ifPresent(item -> {
item.setLastId(
this
.selectLastNewsId(id));
item.setNextId(
this
.selectNextNewsId(id));
taskExecutor.execute(() ->
this
.addReadCount(id, ip));
});
return
news.orElseThrow(() ->
new
BaseException(DataSourceResponseEnum.SELECT_ERROR));
|
来源:https://www.jb51.net/article/209639.htm