本帖最后由 小刀葛小伦 于 2019-8-22 17:08 编辑
Java8新特性:Optional类的正确使用姿势
空指针异常是我们在实际开发中经常会遇到的问题,为了防止程序因为异常而中断,通常要在代码中添加大量的非空验证,例如一个释放 JDBC 相关资源的代码,如下所示。
[Java]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
public
static
void
release(Connection conn,Statement stmt,ResultSet rs) {
try
{
if
(conn !=
null
) {
conn.close();
}
if
(stmt !=
null
) {
stmt.close();
}
if
(rs !=
null
) {
rs.close();
}
}
catch
(SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
|
上述代码中的非空验证并没有多少技术含量,同时会使代码显得臃肿不堪,为了解决这类问题,Java8 引入了 Optional 类,Optional 就是一个容器,它可以保存任意数据类型的值,包括 null,开发者无需进行空值检测,Optional 类的引入很好的解决了实际开发中的空指针异常问题,接下来我们来详细学习 Optional 类的使用。
Optional 常用方法
1、empty(),返回一个空的 Optional 对象,定义如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
|
public
static
<T> Optional<T> empty() {
@SuppressWarnings
(
"unchecked"
)
Optional<T> t = (Optional<T>) EMPTY;
return
t;
}
|
具体操作如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
|
public
class
Test {
public
static
void
main(String[] args) {
Optional optional = Optional.empty();
System.out.println(optional);
}
}
|
2、of(T value),根据传入的 value 创建一个 Optional 对象,定义如下所示。
[Java]
纯文本查看
复制代码
1
2
3
|
public
static
<T> Optional<T> of(T value) {
return
new
Optional<>(value);
}
|
具体操作如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
|
public
class
Test {
public
static
void
main(String[] args) {
Optional optional = Optional.of(
"Hello World"
);
System.out.println(optional);
}
}
|
可以看到输出的结果是 Optional[Hello World],如果要取出 Hello World 直接调用 get 方法即可,如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
|
public
class
Test {
public
static
void
main(String[] args) {
Optional optional = Optional.of(
"Hello World"
);
System.out.println(optional.get());
}
}
|
但是需要注意的是,of 方法不能传 null,否则会抛出空指针异常,如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
|
public
class
Test {
public
static
void
main(String[] args) {
Optional optional = Optional.of(
null
);
System.out.println(optional);
}
}
|
3、ofNullable(T value),和 of(T value) 方法类似,都是用来创建 Optional 对象的,区别在于 ofNullable(T value) 方法可以传 null,定义如下所示。
[Java]
纯文本查看
复制代码
1
2
3
|
public
static
<T> Optional<T> ofNullable(T value) {
return
value ==
null
? empty() : of(value);
}
|
具体操作如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
|
public
class
Test {
public
static
void
main(String[] args) {
Optional optional = Optional.ofNullable(
null
);
System.out.println(optional);
}
}
|
4、get(),返回 Optional 中存储的任意类型值,如果 Optional 中的值为 null,则抛出 java.util.NoSuchElementException,定义如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
|
public
T get() {
if
(value ==
null
) {
throw
new
NoSuchElementException(
"No value present"
);
}
return
value;
}
|
具体操作如下所示。
[Java]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
|
public
class
Test {
public
static
void
main(String[] args) {
Optional optional = Optional.ofNullable(
"Hello World"
);
System.out.println(optional.get());
optional = Optional.ofNullable(
100
);
System.out.println(optional.get());
Integer[] array = {
1
,
2
,
3
,
4
,
5
,
6
};
optional = Optional.ofNullable(array);
System.out.println(optional.get());
}
}
|
如果是下面这种情况,直接抛出 java.util.NoSuchElementException 异常。
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
|
public
class
Test {
public
static
void
main(String[] args) {
Optional optional = Optional.ofNullable(
null
);
System.out.println(optional.get());
}
}
|
5、isPresent(),判断 Optional 存储的值是否存在,返回 true 表示有值,false 表示值不存在,定义如下所示。
[Java]
纯文本查看
复制代码
1
2
3
|
public
boolean
isPresent() {
return
value !=
null
;
}
|
具体使用如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
7
8
|
public
class
Test {
public
static
void
main(String[] args) {
Optional optional = Optional.ofNullable(
"Hello World"
);
System.out.println(optional.isPresent());
optional = Optional.ofNullable(
null
);
System.out.println(optional.isPresent());
}
}
|
6、ifPresent(Consumer<? super T> consumer),如果值存在,执行 Consumer 的具体操作,如果值不存在,不做任何操作,定义如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
|
public
void
ifPresent(Consumer<?
super
T> action) {
if
(value !=
null
) {
action.accept(value);
}
}
|
具体操作如下所示。
[Java]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
|
public
class
Test {
public
static
void
main(String[] args) {
//值存在
List<Integer> list = Arrays.asList(
1
,
2
,
3
,
4
,
5
,
6
);
Optional optional = Optional.ofNullable(list);
System.out.print(
"值存在:"
);
optional.ifPresent(System.out::println);
//值不存在
optional = Optional.ofNullable(
null
);
System.out.print(
"值不存在:"
);
optional.ifPresent((str)-> System.out.println(str));
}
}
|
7、ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction),如果值存在,执行 Consumer 的具体操作,如果值不存在,执行 emptyAction 的具体操作,定义如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
7
|
public
void
ifPresentOrElse(Consumer<?
super
T> action, Runnable emptyAction) {
if
(value !=
null
) {
action.accept(value);
}
else
{
emptyAction.run();
}
}
|
具体操作如下所示。
[Java]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
|
public
class
Test {
public
static
void
main(String[] args) {
//值存在
List<Integer> list = Arrays.asList(
1
,
2
,
3
,
4
,
5
,
6
);
Optional optional = Optional.ofNullable(list);
System.out.print(
"值存在:"
);
optional.ifPresentOrElse(System.out::println,()-> System.out.println(
"value is null"
));
//值不存在
optional = Optional.ofNullable(
null
);
System.out.print(
"值不存在:"
);
optional.ifPresentOrElse(System.out::println,()-> System.out.println(
"value is null"
));
}
}
|
8、filter(Predicate<? super T> predicate),根据传入的 Predicate 对 Optional 中的值进行过滤,满足条件则返回该 Optional 对象,否则返回一个空的 Optional,定义如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
7
8
|
public
Optional<T> filter(Predicate<?
super
T> predicate) {
Objects.requireNonNull(predicate);
if
(!isPresent()) {
return
this
;
}
else
{
return
predicate.test(value) ?
this
: empty();
}
}
|
具体操作如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
7
8
9
|
public
class
Test {
public
static
void
main(String[] args) {
Optional optional = Optional.ofNullable(
1
);
Predicate<Integer> predicate = num -> num >=
3
;
System.out.println(optional.filter(predicate));
predicate = num -> num <
3
;
System.out.println(optional.filter(predicate));
}
}
|
9、map(Function<? super T, ? extends U> mapper),如果 Optional 有值,则执行 mapper 映射函数,并获取其返回值,如果返回值不为 null,则返回一个包含返回值的 Optional 对象,否则返回一个空的 Optional 对象,定义如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
7
8
|
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));
}
}
|
具体操作如下所示。
[Java]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
public
class
Test {
public
static
void
main(String[] args) {
ClassB classB =
new
ClassB();
ClassA classA =
new
ClassA();
classA.setClassB(classB);
Optional optional = Optional.ofNullable(classA)
.map((classA1)->classA1.getClassB());
System.out.println(optional);
}
}
class
ClassA {
private
ClassB classB;
public
ClassB getClassB() {
return
classB;
}
public
void
setClassB(ClassB classB) {
this
.classB = classB;
}
}
class
ClassB {
}
|
上述代码表示如果 classA 中包含 classB,则直接返回一个 Optional[ClassB] 对象,否则返回一个空的 Optional 对象,
对上述代码进行修改,删除 classA.setClassB(classB); 如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
|
ClassB classB =
new
ClassB();
ClassA classA =
new
ClassA();
Optional optional = Optional.ofNullable(classA)
.map((classA1)->classA1.getClassB());
System.out.println(optional);
|
这里需要注意的是 map 方法的调用必须和 Optional 的创建连起来写,如下所示。
[Java]
纯文本查看
复制代码
1
|
Optional optional = Optional.ofNullable(classA).map((classA1)->classA1.getClassB());
|
不能分开写,错误写法如下所示。
[Java]
纯文本查看
复制代码
1
2
|
Optional optional = Optional.ofNullable(classA);
optional.map((classA1)->classA1.getClassB());
|
10、flatMap(Function<? super T, ? extends Optional<? extends U>> mapper),功能与 map 类似,区别在于 map 的 mapper 映射函数可返回任意数据类型,但是 flatMap 的 mapper 映射函数只能返回 Optional 类型,定义如下所示。
[Java]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
|
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);
}
}
|
具体操作如下所示。
[Java]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
|
public
class
Test {
public
static
void
main(String[] args) {
ClassB classB =
new
ClassB();
ClassA classA =
new
ClassA();
classA.setClassB(classB);
Optional optional = Optional.ofNullable(classA)
.flatMap((classA1)->{
return
Optional.ofNullable(classA1.getClassB());
});
System.out.println(optional);
}
}
|
11、orElse(T other),如果 Optional 的值存在则返回,否则返回 other,定义如下所示。
[Java]
纯文本查看
复制代码
1
2
3
|
public
T orElse(T other) {
return
value !=
null
? value : other;
}
|
具体操作如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
7
8
|
public
class
Test {
public
static
void
main(String[] args) {
Optional optional = Optional.ofNullable(
1
);
System.out.println(optional.orElse(
"value is null"
));
optional = Optional.ofNullable(
null
);
System.out.println(optional.orElse(
"value is null"
));
}
}
|
12、orElseGet(Supplier<? extends T> supplier),功能与 orElse 类似,区别在于 orElse 可直接返回某个值,orElseGet 需要执行 supplier,并返回其结果,多了一个步骤,定义如下所示。
[Java]
纯文本查看
复制代码
1
2
3
|
public
T orElseGet(Supplier<?
extends
T> supplier) {
return
value !=
null
? value : supplier.get();
}
|
具体操作如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
7
8
|
public
class
Test {
public
static
void
main(String[] args) {
Optional optional = Optional.ofNullable(
1
);
System.out.println(optional.orElseGet(()->
"value is null"
));
optional = Optional.ofNullable(
null
);
System.out.println(optional.orElseGet(()->
"value is null"
));
}
}
|
13、orElseThrow(),如果值存在则返回,否则抛出 NoSuchElementException,定义如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
|
public
T orElseThrow() {
if
(value ==
null
) {
throw
new
NoSuchElementException(
"No value present"
);
}
return
value;
}
|
具体操作如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
7
8
|
public
class
Test {
public
static
void
main(String[] args) {
Optional optional = Optional.ofNullable(
1
);
System.out.println(optional.orElseThrow());
optional = Optional.ofNullable(
null
);
System.out.println(optional.orElseThrow());
}
}
|
14、orElseThrow(Supplier<? extends X> exceptionSupplier),功能与 orElseThrow 类似,如果值存在则返回,否则抛出 exceptionSupplier 返回的异常,定义如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
7
|
public
<X
extends
Throwable> T orElseThrow(Supplier<?
extends
X> exceptionSupplier)
throws
X {
if
(value !=
null
) {
return
value;
}
else
{
throw
exceptionSupplier.get();
}
}
|
具体操作如下所示。
[Java]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
public
class
Test {
public
static
void
main(String[] args) {
Optional optional = Optional.ofNullable(
1
);
try
{
System.out.println(optional.orElseThrow(()->{
throw
new
IllegalStateException();}));
}
catch
(Throwable throwable) {
throwable.printStackTrace();
}
optional = Optional.ofNullable(
null
);
try
{
System.out.println(optional.orElseThrow(()->{
throw
new
IllegalStateException();}));
}
catch
(Throwable throwable) {
throwable.printStackTrace();
}
}
}
|
上面详细介绍了 Optional 类的各种方法,接下来我们结合实际案例,来看看实际开发中使用 Optional 的优势。
实际案例
我们来设置一个客户订单查询场景。
1、定义 3 个类 Consumer、Order、Product,其中 Consumer 包含 Order,Order 包含 Product,具体代码如下所示。
[Java]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public
class
Consumer {
private
Order order;
public
Order getOrder() {
return
order;
}
public
void
setOrder(Order order) {
this
.order = order;
}
}
public
class
Order {
private
Product product;
public
Product getProduct() {
return
product;
}
public
void
setProduct(Product product) {
this
.product = product;
}
}
public
class
Product {
private
String name;
public
String getName() {
return
name;
}
public
void
setName(String name) {
this
.name = name;
}
}
|
2、分别创建 Consumer、Order、Product 对象,并完成级联,然后定义返回 Consumer 中 ProductName 的方法,传统的开发方式需要对涉及到的对象都进行非空验证,如下所示。
[Java]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public
class
Test {
public
static
void
main(String[] args) {
Product product =
new
Product();
product.setName(
"电脑"
);
Order order =
new
Order();
order.setProduct(product);
Consumer consumer =
new
Consumer();
consumer.setOrder(order);
System.out.println(getProductName(consumer));
}
public
static
String getProductName(Consumer consumer){
if
(consumer !=
null
){
Order order = consumer.getOrder();
if
(order !=
null
){
Product product = order.getProduct();
if
(product !=
null
){
return
product.getName();
}
}
}
return
null
;
}
}
|
3、使用 Optional 类对上述代码进行修改,可以将代码变得更加简洁、优雅,不需要一层一层的写非空判断,可直接完成链式调用,如下所示。
[Java]
纯文本查看
复制代码
1
2
3
4
5
6
7
|
public
static
String getProductName(Consumer consumer){
return
Optional.ofNullable(consumer)
.map(consumer1 -> consumer1.getOrder())
.map(order -> order.getProduct())
.map(product -> product.getName())
.orElse(
null
);
}
|
|