Fellow Travellers

Java 8 之Optional

万世威
字数统计: 879阅读时长: 4 min
2018/10/23 Share

Java8–Optional

一、基本示例

​ Optional 是 Java8 提供的了 为了解决 Null 安全问题的一个 API 。善用Optional可以使我们代码中很多繁琐、丑陋的设计变得十分优雅 。

看一个示例:

1
2
3
4
5
public static String getName(User u) {
if (u == null)
return "Unknown";
return u.name;
}

改写成下面的形式和上面的没有什么太大区别。

1
2
3
4
5
6
public static String getName(User u) {
Optional<User> user = Optional.ofNullable(u);
if (!user.isPresent())
return "Unknown";
return user.get().name;
}

正确示例:

1
2
3
4
5
public static String getName(User u) {
return Optional.ofNullable(u)
.map(user->user.name)
.orElse("Unknown");
}

再来一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
public static String getChampionName(Competition comp) throws IllegalArgumentException {
if (comp != null) {
CompResult result = comp.getResult();
if (result != null) {
User champion = result.getChampion();
if (champion != null) {
return champion.getName();
}
}
}
throw new IllegalArgumentException("The value of param comp isn't available.");
}

改造后:

1
2
3
4
5
6
7
public static String getChampionName(Competition comp) throws IllegalArgumentException {
return Optional.ofNullable(comp)
.map(c->c.getResult())
.map(r->r.getChampion())
.map(u->u.getName())
.orElseThrow(()->new IllegalArgumentException("The value of param comp isn't available."));
}

使用Optional 可以配合 Stream 实现更优雅的写法。

二、Optional API 介绍

1
2
3
4
5
6
7
8
/**
* Common instance for {@code empty()}.
*/
private static final Optional<?> EMPTY = new Optional<>();
/**
* If non-null, the value; if null, indicates no value is present
*/
private final T value;

构造函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* Constructs an empty instance.
* @implNote Generally only one empty instance, {@link Optional#EMPTY},
* should exist per VM.
*/
private Optional() {
this.value = null;
}

/**
* Constructs an instance with the value present.
* @param value the non-null value to be present
* @throws NullPointerException if value is null
*/
private Optional(T value) {
this.value = Objects.requireNonNull(value);
}

构造Optional的三种方式:

1
2
3
4
5
6
7
8
9
10
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
public static<T> Optional<T> empty() {
Optional<T> t = (Optional<T>) EMPTY;
return t;
}

常用方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 把对象放到容器里,对象为null,创建一个空容器
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}

// 和 Stream 中一样的用法
public Optional<T> filter(Predicate<? super T> predicate) {...}
public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {...}
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {...}

// 容器的值 == null,返回 other、否则返回 value
public T orElse(T other) {
return value != null ? value : other;
}
// 同上面类似
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
// 同上, 会抛出异常
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {...}

三、详解

1、orElse 存在即返回, 无则提供默认值

1
2
3
//而不是 return user.isPresent() ? user.get() : null;
return user.orElse(null);
return user.orElse(UNKNOWN_USER);

2、orElseGet 存在即返回, 无则由函数来产生

1
2
//而不要 return user.isPresent() ? user: fetchAUserFromDatabase();
return user.orElseGet(() -> fetchAUserFromDatabase());

3、ifPresent 存在才执行操作

1
2
3
4
5
6
7
// 正确示例
user.ifPresent(System.out::println);

//而不要下边那样
if (user.isPresent()) {
System.out.println(user.get());
}

4、map:如果有值,则对其执行调用mapping函数得到返回值。如果返回值不为null,则创建包含mapping返回值的Optional作为map方法返回值,否则返回空Optional

1
2
3
4
5
6
7
8
9
10
11
12
13
List<String> names = Arrays.asList("zhuxiaoming", "wangdachui", null);
for (String name : names) {
Optional<String> upperName = Optional.ofNullable(name)
.map(value -> value.toUpperCase());
// 方法调用方式
// Optional<String> upperName = Optional.ofNullable(name).map(String::toUpperCase);
System.out.println(upperName.orElse("No value found"));
}

// result
ZHUXIAOMING
WANGDACHUI
No value found

5、filter:如果有值并且满足断言条件返回包含该值的Optional,否则返回空Optional

1
2
3
4
5
6
7
8
9
for (String name : names) {
Optional<String> optional = Optional.ofNullable(name)
.filter(value -> value.length() > 7);
System.out.println(optional.orElse("less than 7 characters"));
}
// result
zhuxiaoming
wangdachui
less than 7 characters
CATALOG
  1. 1. Java8–Optional
    1. 1.1. 一、基本示例
    2. 1.2. 二、Optional API 介绍
    3. 1.3. 三、详解