Optional

回顾上午的问题

public class A {

    private B b;

    public B getB() {
        return b;
    }

    public void setB(B b) {
        this.b = b;
    }
}

public class B {

    private String bName;
    private String bAge;

    public String getbName() {
        return bName;
    }

    public void setbName(String bName) {
        this.bName = bName;
    }

    public String getbAge() {
        return bAge;
    }

    public void setbAge(String bAge) {
        this.bAge = bAge;
    }
}
复制代码

已经存在两个类,并且互相嵌套,而且不允许修改, A 、B 两个类的结构,我们要安全的访问 A B中的值,尽可能少的使用 if 语句。

A a = null;
Optional<A> a1 = Optional.ofNullable(a);
Optional<B> b = a1.filter((t) -> t.getB() != null).map(A::getB);
// 上面一行代码的问题是, t 有可能会为 null ,从而引发 NPE
B b2 = b.get();
复制代码
Optional<A> a1 = Optional.ofNullable(a);
Optional<B> b = a1.map(A::getB);
b.get(); // 有可能会抛异常,因为如果 b 为 null,那么得到的 Optional 为 empty 创建的
b.orElse(new B()); // 没有问题,返回 new B 的对象
b.orElseGet(() -> B :: new); // 没有问题,返回 new B 的对象
b.orElseThrow(() -> YdException::new);  // 手动抛出异常
复制代码

使用 Optional 带来的变化

public class PersonNoOptional {

    private Car car;

    public Car getCar() {
        return car;
    }

    public void setCar(Car car) {
        this.car = car;
    }

    public static class Car{
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}
复制代码

上面的代码是没有使用 Optional 时候,我们经常会写的样式。会出现的问题:

  • 如果某个值为 null,立马会报出 NPE

我们的解决方式

public class OptionService {

    public void opt() {
        PersonNoOptional p = new PersonNoOptional();

        PersonNoOptional.Car car = p.getCar();
        if (car != null) {
            // ....
        }
    }
    
}
复制代码

会添加很多的 if 来进行判断,甚至还有空对象设计模式(Null Object Pattern) 来处理这一类的问题。Java 8 为我们带来了 Optional 添加新的解决方式。

public class PersonOptional {
    private Optional<PersonNoOptional.Car> car;

    public Optional<PersonNoOptional.Car> getCar() {
        return car;
    }

    public void setCar(PersonNoOptional.Car car) {
        this.car = Optional.of(car);
    }

    public static class Car {
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}
复制代码

Peron 有可能会没有 Car,但是每一辆 Car 都必须有 name,所以我们对 Car 使用了 Optional 包装,而 name 没有使用 Optional 的原因就在这里。

Optional 的创建

empty

创建一个空的 Optional 对象

Optional<Object> empty = Optional.empty();
复制代码

empty() 方法的实现

private static final Optional<?> EMPTY = new Optional<>();

private Optional() { this.value = null; }

public static<T> Optional<T> empty() {
  @SuppressWarnings("unchecked")
  Optional<T> t = (Optional<T>) EMPTY;
  return t;
}
复制代码

of

Optional<B> optionalB = Optional.of(new B());
复制代码

of 方法中的参数如果为 null,会发生 NPE

Optional<Object> optional = Optional.of(null);
复制代码

of() 方法的实现

// Objects.requireNonNull 的实现
public static <T> T requireNonNull(T obj) {
  if (obj == null)
    throw new NullPointerException();
  return obj;
}

private Optional(T value) {
  this.value = Objects.requireNonNull(value);
}

public static <T> Optional<T> of(T value) {
  return new Optional<>(value);
}
复制代码

ofNullable

ofNullable 允许传入的参数为 null

A a = null;
Optional<A> optonal = Optional.ofNullable(a);
复制代码

ofNullable 的实现

public static <T> Optional<T> ofNullable(T value) {
  return value == null ? empty() : of(value);
}
复制代码

#Optinal 中获取值

get

A a = optionalA.get();
复制代码

如果 Optional 容器中不存在值,会抛出异常 NoSuchElementException("No value present")

get 的实现

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

orElse

A a = optionalA.orElse(new A());
复制代码

如果 Optional 容器中不存在值,使用 orElse 方法中定义的值。

orElse 的实现

public T orElse(T other) {
  return value != null ? value : other;
}
复制代码

orElseGet

A a = optionalA.orElseGet(A::new);
复制代码

如果 Optional 容器中不存在值,会执行定义的函数。

orElseGet 的实现

public T orElseGet(Supplier<? extends T> other) {
  return value != null ? value : other.get();
}
复制代码

orElseThrow

A a = optionalA.orElseThrow(RuntimeException::new);
复制代码

如果 Optional 容器中不存在值,会抛出指定的异常。与 get 方法的区别是,get 方法抛出的异常为固定的,该方法可以抛出指定的异常。

orElseThrow 的实现

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
  if (value != null) {
    return value;
  } else {
    throw exceptionSupplier.get();
  }
}
复制代码

Optional 容器中的值为空时,使用了 throw 关键字。

map 和 flatMap

map

public class A {
    private B b;
    public B getB() {
        return b;
    }
}

public class B {
    private Name bName;
    private String bAge;
    public Name getbName() {
        return bName;
    }

    public void setbName(Name bName) {
        this.bName = bName;
    }

    public String getbAge() {
        return bAge;
    }

    public void setbAge(String bAge) {
        this.bAge = bAge;
    }

    public static class Name{
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
}
复制代码

A B 两个类的结构关系是互相嵌套,我们要取出 b.Name.getName() 的值

Optional<String> aName = optionalA.map(A::getB)
  .map(B::getbName)
  .map(B.Name::getName);
System.out.println(aName.orElse("kkk"));
复制代码

flatMap

如果 B 在 A 的嵌套中,使用了 Optional 包装

public class A {

    private Optional<B> b;

    public Optional<B> getB() {
        return b;
    }
}
复制代码

再使用上面的访问,就会编译报错。

原因:

Optional<Optional<B>> optional = optionalA.map(A::getB);
复制代码

map 的返回外面被包装了一层 Optional ,想要达到上面的效果,需要拆掉一层 Optional 的包装,那么此时就可以使用 flatMap 来打散一层 Optional 的包装

String kkk = optionalA.flatMap(A::getB)
  .map(B::getbName)
  .map(B.Name::getName)
  .orElse("kkk");
复制代码

ypxh就可以顺利访问了

map 和 flatMap 的区别在于,flatMap 会进行拆包(将外面的层包装拆除)的动作,而 map 不会进行拆包

Optional 提供的其他方法

isPresent

isPresent 用于判断 Optional 容器中值是否为空(null),不为空返回会 true,空返回 false

public boolean isPresent() {
  return value != null;
}
复制代码

ifPresent

ifPresent 提供了执行函数式代码的能力,当 Optional 容器中的值不为空时,会执行传入的函数式代码。

optionalA.ifPresent(c -> System.out.println(c.getB()));
复制代码

ifPresent 的实现

public void ifPresent(Consumer<? super T> consumer) {
  if (value != null)
    consumer.accept(value);
}
复制代码

filter

通过执行传入的谓词 进行过滤,如果传入的 谓词 执行结果为 true 返回 Optional 容器本身,否则返回空容器。

public Optional<T> filter(Predicate<? super T> predicate) {
  Objects.requireNonNull(predicate);
  if (!isPresent())
    return this;
  else
    return predicate.test(value) ? this : empty();
}
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值