2

Optional源码解析与实践

 1 year ago
source link: https://blog.51cto.com/u_15714439/5721827
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

NullPointerException在开发过程中经常遇到,稍有不慎小BUG就出现了,如果避免这个问题呢,Optional就是专门解决这个问题的类,那么Optional如何使用呢?让我们一起探索一下吧!

2 源码解析

2.1 Optional定义

Optional类是Java8为了解决null值判断问题而创建的容器类,在java.util 下,使用Optional类可以避免显式的null值判断,避免null导致的NullPointerException。首先,Optional是一个容器,它可以保存类型T的值,也可以为null的容器对象。Optional容器只能存一个值。

2.2 Optional的属性

1)源码:

/**
* Common instance for {@code
private static final Optional<?> EMPTY = new Optional<>();


/**
* If non-null, the value; if null, indicates no value is present
*/
private final T value;

根据源码可以看到Optional有两个属性,一个是为空值准备的EMPTY和泛型值value;

2.3 Optional的方法

Optional除toString()、hashCode() 、equals()等Object的方法外,还包含以下方法。

2.3.1 私有构造方法

/**
* 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);
}

分别是创建一个空实例和构造一个具有当前值的实例。

2.3.2 创建方法

1)源码

public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
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);
}

2)方法说明

  • empty(): 创建一个空的 Optional 实例
  • of(T t) : 创建一个 Optional 实例,当 t为null时抛出异常
  • ofNullable(T t): 创建一个 Optional 实例,但当 t为null时不会抛出异常,而是返回一个空的实例

3)测试代码

public static void main(String[] args) {
Integer value1 = null;
Integer value2 = 1;
try {
Optional<Integer> optional1 = Optional.empty();
System.out.println("optional1创建了");
}catch (Exception e){
System.out.println("optional1失败了");
}
try {
Optional<Integer> optional2 = Optional.of(value1);
System.out.println("optional2创建了");
}catch (Exception e){
System.out.println("optional2失败了");
}
try {
Optional<Integer> optional3 = Optional.ofNullable(value1);
System.out.println("optional3创建了");
}catch (Exception e){
System.out.println("optional3失败了");
}
try {
Optional<Integer> optional4 = Optional.of(value2);
System.out.println("optional4创建了");
}catch (Exception e){
System.out.println("optional4失败了");
}
try {
Optional<Integer> optional5 = Optional.ofNullable(value2);
System.out.println("optional5创建了");
}catch (Exception e){
System.out.println("optional5失败了");
}
}

4)运行结果

Optional源码解析与实践_映射函数

2.3.3 值获取方法

1)源码

public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}

2)方法说明

get(): 如果Optional不为空,则返回该Optional容器中的值,否则抛出NoSuchElementExceptio 。

3)测试代码

public static void main(String[] args) {
Integer value1 = null;
Integer value2 = 1;
Optional<Integer> optional1 = Optional.ofNullable(value1);
Optional<Integer> optional2 = Optional.of(value2);
try {
Integer result=optional1.get();
System.out.println("optional1的值是:"+result);
}catch (Exception e){
System.out.println("optional1的值获取失败,原因:"+e.getMessage());
}
try {
Integer result=optional2.get();
System.out.println("optional2的值是:"+result);
}catch (Exception e){
System.out.println("optional2的值获取失败,原因:"+e.getMessage());
}
}

4)运行结果

Optional源码解析与实践_NullPointerException_02

2.3.4 判断方法

1)源码

public boolean isPresent() {
return value != null;
}
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(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 {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}

2)方法说明

  • isPresent(): 判断optional是否为空,如果空则返回false,否则返回true
  • ifPresent(Consumer c): 如果optional不为空,则将optional中的对象传给Comsumer函数
  • orElse(T other): 如果optional不为空,则返回optional中的对象;如果为null,则返回 other 这个对象。
  • orElseGet(Supplier other): 如果optional不为空,则返回optional中的对象;如果为null,否则调用其他函数并返回调用的结果
  • orElseThrow(Supplier exception): 如果optional不为空,则返回optional中的对象;如果为null,则抛出Supplier函数生成的异常

3)测试代码

public static void main(String[] args) {
Integer value1 = null;
Integer value2 = 1;
Optional<Integer> optional1 = Optional.ofNullable(value1);
Optional<Integer> optional2 = Optional.of(value2);
try {
if(optional1.isPresent()){
System.out.println("optional1的isPresent结果不为空");
}else{
System.out.println("optional1的isPresent结果为空");
}
}catch (Exception e){
System.out.println("optional1的isPresent判空失败,原因:"+e.getMessage());
}
try {
if(optional2.isPresent()){
System.out.println("optional2的isPresent结果不为空");
}else{
System.out.println("optional2的isPresent结果为空");
}
}catch (Exception e){
System.out.println("optional2的isPresent判空失败,原因:"+e.getMessage());
}


optional1.ifPresent(t->{
int i =t+1;
System.out.println("optional1处理后的值是"+i);
});
optional2.ifPresent(t->{
int i =t+1;
System.out.println("optional2处理后的值是"+i);});


Integer value3 = 2;
Integer result = optional1.orElse(value3);
System.out.println("optional1执行orElse处理后的值是"+result);


result = optional2.orElse(value3);
System.out.println("optional2执行orElse处理后的值是"+result);


result = optional1.orElseGet(()-> new Integer(-1));
System.out.println("optional1执行orElseGet处理后的值是"+result);


result = optional2.orElseGet(()-> new Integer(-1));
System.out.println("optional2执行orElseGet处理后的值是"+result);
try {
result = optional1.orElseThrow (()-> new RuntimeException("值是空的"));
System.out.println("optional1执行orElseThrow处理后的值是"+result);
}catch (Exception e){
System.out.println("optional1的orElseThrow抛出异常:"+e.getMessage());
}
try {
result = optional2.orElseThrow (()-> new RuntimeException("值是空的"));
System.out.println("optional2执行orElseThrow处理后的值是"+result);
}catch (Exception e){
System.out.println("optional2的orElseThrow抛出异常:"+e.getMessage());

4)运行结果

Optional源码解析与实践_Optional_03

2.3.5 过滤方法

1)源码

public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent())
return this;
else
return predicate.test(value) ? this : empty();
}

2)方法说明

filter(Predicate p): 如果optional不为空,则执行Predicate p,如果p的结果为true,则返回原本的optional,否则返回空的optional

3)测试代码

public static void main(String[] args) {
Integer value1 = 5;
Integer value2 = 6;
Optional<Integer> optional1 = Optional.ofNullable(value1);
Optional<Integer> optional2 = Optional.of(value2);


Optional<Integer> result =optional1.filter(t->t > 5);
System.out.println("optional1的filter后的值:"+result);
result =optional2.filter(t->t > 5);
System.out.println("optional2的filter后的值:"+result);

4)运行结果

Optional源码解析与实践_映射函数_04

2.3.6 映射方法

1)源码

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));
}
}
public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent())
return empty();
else {
return Objects.requireNonNull(mapper.apply(value));
}
}

2)方法说明

  • map(Function mapper): 如果存在一个值,则对其应用提供的映射函数,如果结果非空,则返回描述结果的Optional。 否则返回一个空的Optional。
  • flatMap(Function< T,Optional> mapper): 如果有值,则对其应用提供的可选映射函数,返回结果,否则返回空的可选函数。 这个方法类似于map(Function),但是提供的映射器的结果已经是一个可选的,如果调用,flatMap不会用额外的可选的包装它。
  • 区别:map会自动将u放到optional中,而flatMap则需要手动给u创建一个optional

3)测试代码

public static void main(String[] args) {
User user1 = null;
User user2 = new User("user2名字",19);
Optional<User> optional1 = Optional.ofNullable(user1);
Optional<User> optional2 = Optional.of(user2);
System.out.println("=========map==========");
System.out.println("optional1的map前的值:"+optional1);
Optional<String> result =optional1.map(t->t.getName());
System.out.println("optional1的map后的值:"+result);


System.out.println("optional2的map前的值:"+optional2);
result =optional2.map(t->t.getName());
System.out.println("optional2的map后的值:"+result);


System.out.println("===========flatMap========");


System.out.println("optional1的flatMap前的值:"+optional1);
Optional<Integer> result2 =optional1.flatMap(t->Optional.ofNullable(t.getAge()));
System.out.println("optional1的flatMap后的值:"+result2);


System.out.println("optional2的flatMap前的值:"+optional2);
result2 =optional2.flatMap(t->Optional.ofNullable(t.getAge()));
System.out.println("optional2的flatMap后的值:"+result2);

}
public class User {
String name;
Integer age;
public User(String name,Integer age){
this.name = name;
this.age=age;
}


public String getName() {
return name;
}


public Integer getAge() {
return age;

4)运行结果

Optional源码解析与实践_抛出异常_05

3 应用实例

3.1 错误用法

  • 由于Optional并没有实现Serializable接口,所以不能作为类的属性。
  • 不要把Optional作为方法的参数。
  • 把if(x!=null)直接换成Optional.ofNullable(x).isPresent(),这样有过度编码的嫌疑。
  • 直接使用Optional.get()的返回值进行操作,String result =Optional.ofNullable(null).get().toString();这样还是会抛出异常的。

3.2 建议用法

A类有属性B类,B类有属性C类,C类有name这个字段。
使用Optional之前:

if(atest!=null){
Btest btest =atest.getBtest();
if(btest!=null){
Ctest ctest = btest.getCtest();
if (ctest != null) {
name =ctest.getName();
}
}
}

使用Optional之后:

name = Optional.ofNullable(atest).map(t->t.getBtest()).map(t->t.getCtest()).map(t->t.getName()).orElse("默认值");

代码是不是看上去更整洁了呢?

通过对Optional源码解析和用例测试代码的运行结果,可以看出使用Optional可以优化null值判断代码,让代码变得更加优雅和整洁。


作者:陈昌浩


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK