0%

Optional 详解

定义

  1. Optional 的出现主要为了解决 NullPointerExcepton 的异常。

  2. Optional 是一个值的容器,用来存储一个 Object 或者 null

  3. 它是一个基于值的类(value-base class)

    基于值的类(value-base class) 需要满足以下几个条件:

    1. 必须为 final 和 不可变的(可以包含可变对象的引用);
    2. 必须实现 equalshashCodetoString 方法。并且这些方法必须仅根据当前实例的状态独自计算,而不是根据他的标识或者其他对象的状态、变量计算;
    3. 不使用身份敏感的操作,例如实例之间通过引用的 == 来判等、实例的 hashCode 已经实例内在的锁;
    4. 两个实例的相等,仅仅基于 equals() 方法,而不基于引用的相等(==);
    5. 没有可访问的构造方法(构造方法为私有),仅仅通过工厂方法来实例化对象,但是工厂方法不保证返回实例的一致性(即:第一次调用与第二次调用可能返回的实例是不同的);
    6. 如果使用 equals 方法判断两个实例是相同的,那么这两个实例之间可以随意替换。

static 方法

  1. empty() 构造一个包含的值为 nullOptional 对象;

  2. of() 构造一个包含的值不为 nullOptional 对象;

  3. ofNullable() 构造一个包含的值可为 null 也可不为 nullOptional 对象;

一些方法

ifPresent 方法

1
2
3
4
5
6
7
8
9
10
11
12
/**
* If a value is present, invoke the specified consumer with the value,
* otherwise do nothing.
*
* @param consumer block to be executed if a value is present
* @throws NullPointerException if value is present and {@code consumer} is
* null
*/
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}

该方法接收一个 Consumer 对象,并且当 Optional 对象中包含的值不为 null 的时候,调用 Consumer 对象的 accept 方法.

这个方法可以提供给我们的便利是,判断当一个对象不为空的时候去做一些事情,比如

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
package info.andrewei;

import java.util.Optional;

/**
* @author Andrewei
*/
public class Main {
public static void main(String[] args) {
Main ma = new Main();
ma.print(null);
ma.print("hello");
}

public void print(String str) {
// 第一种写法
if (null != str) {
System.out.println(str);
}

// 第二种写法
Optional<String> optional = Optional.ofNullable(str);
optional.ifPresent(System.out::println);
}
}

orElse 方法

1
2
3
4
5
6
7
8
9
10
/**
* Return the value if present, otherwise return {@code other}.
*
* @param other the value to be returned if there is no value present, may
* be null
* @return the value, if present, otherwise {@code other}
*/
public T orElse(T other) {
return value != null ? value : other;
}

该方法接收一个与当前 Optional 对象包含的值类型相同的对象参数,当前 Optional 对象包含的值为 null 时,返回传入的参数,否则返回当前包含的值。

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
package info.andrewei;

import java.util.Optional;

/**
* @author Andrewei
*/
public class Main {
public static void main(String[] args) {
Main ma = new Main();
ma.print(null);
ma.print("hello");
}

public void print(String str) {
// 第一种写法
if (null != str) {
System.out.println(str);
} else {
System.out.println("world");
}

// 第二种写法
Optional<String> optional = Optional.ofNullable(str);
System.out.println(optional.orElse("world"));
}
}

orElseGet 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* Return the value if present, otherwise invoke {@code other} and return
* the result of that invocation.
*
* @param other a {@code Supplier} whose result is returned if no value
* is present
* @return the value if present otherwise the result of {@code other.get()}
* @throws NullPointerException if value is not present and {@code other} is
* null
*/
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}

orElase 不同的是,该方法传入的参数为 Supplier 的对象,当前 Optional 对象包含的值为 null 时,该方法会调用 Supplier 对象的 get() 方法来生成一个值返回。

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
package info.andrewei;

import java.util.Optional;

/**
* @author Andrewei
*/
public class Main {
public static void main(String[] args) {
Main ma = new Main();
ma.print(null);
ma.print("hello");
}

public void print(String str) {
// 第一种写法
if (null != str) {
System.out.println(str);
} else {
System.out.println("world");
}

// 第二种写法
Optional<String> optional = Optional.ofNullable(str);
System.out.println(optional.orElseGet(() -> "world"));
}
}

map 方法

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
/**
* If a value is present, apply the provided mapping function to it,
* and if the result is non-null, return an {@code Optional} describing the
* result. Otherwise return an empty {@code Optional}.
*
* @apiNote This method supports post-processing on optional values, without
* the need to explicitly check for a return status. For example, the
* following code traverses a stream of file names, selects one that has
* not yet been processed, and then opens that file, returning an
* {@code Optional<FileInputStream>}:
*
* <pre>{@code
* Optional<FileInputStream> fis =
* names.stream().filter(name -> !isProcessedYet(name))
* .findFirst()
* .map(name -> new FileInputStream(name));
* }</pre>
*
* Here, {@code findFirst} returns an {@code Optional<String>}, and then
* {@code map} returns an {@code Optional<FileInputStream>} for the desired
* file if one exists.
*
* @param <U> The type of the result of the mapping function
* @param mapper a mapping function to apply to the value, if present
* @return an {@code Optional} describing the result of applying a mapping
* function to the value of this {@code Optional}, if a value is present,
* otherwise an empty {@code Optional}
* @throws NullPointerException if the mapping function is null
*/
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));
}
}

map 方法接收一个 Function 对象。返回一个新的 Optional 对象。

当前 Optiaon 对象包含的值为 null 时,返回一个包含 null 对象的 Optional 对象;当前 Optional 包含的值 value 不为 null 时,通过在 value 上应用 Function 对象的 apply 方法得到新值 value1 并构造一个包含 value1 的新 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
package info.andrewei;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

/**
* @author Andrewei
*/
public class Main {
public static void main(String[] args) {
Main ma = new Main();

Person p1 = new Person();
p1.setName("zhangsan");
p1.setAge(10);

Person p2 = new Person();
p2.setName("lisi");
p2.setAge(20);

Company company = new Company();
company.setName("company1");
company.setPersonList(Arrays.asList(p1, p2));

System.out.println(ma.getCompanyPersons(null));
System.out.println(ma.getCompanyPersons(new Company()));
System.out.println(ma.getCompanyPersons(company));

}

public List<Person> getCompanyPersons(Company company) {
Optional<Company> optional = Optional.ofNullable(company);
return optional.map(Company::getPersonList).orElse(Collections.emptyList());
}

static class Company {
String name;
List<Person> personList;

public String getName() {
return name;
}

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

public List<Person> getPersonList() {
return personList;
}

public void setPersonList(List<Person> personList) {
this.personList = personList;
}
}

static class Person {
String name;
int age;

public String getName() {
return name;
}

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

public int getAge() {
return age;
}

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

@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
}

filter 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* If a value is present, and the value matches the given predicate,
* return an {@code Optional} describing the value, otherwise return an
* empty {@code Optional}.
*
* @param predicate a predicate to apply to the value, if present
* @return an {@code Optional} describing the value of this {@code Optional}
* if a value is present and the value matches the given predicate,
* otherwise an empty {@code Optional}
* @throws NullPointerException if the predicate is null
*/
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}

该方法传入一个 Predicate 对象,当前 Optiaonal 包含的值 valuenull 或者在 value 上应用 Predicate 对象的 test 方法返回 false 时,该方法返回空的 Predicate 否则返回自身。

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
package info.andrewei;

import java.util.Optional;

/**
* @author Andrewei
*/
public class Main {

public static void main(String[] args) {
Main ma = new Main();

ma.print(null);
ma.print("abc");
ma.print("abcd");

}

public void print(String str) {
Optional<String> optional = Optional.ofNullable(str);

Optional<String> newOpt = optional.filter(s -> s.length() > 3);
System.out.println(newOpt.orElse("no print"));
}
}