NPE问题
NPE 即(java.lang.NullPointException):空指针异常,在日常编程中常常会遇到的问题。通常需要使用者对传入参数或者调用返回结果进行空指针(null)判断,java8之前一般的代码如下:
public String getUserAddressArea(User user) {
if (user != null) {
if (user.getAddress() != null) {
return user.getAddress().getArea();
}
}
return null;
}
如果业务对象嵌套了多层对象,那么如果按照上面的写法if也会嵌套多层。虽然可以使用卫语句进行优化但是代码依旧丑陋(多层嵌套会有多个if,如果还有其它判断条件则会使得if更加复杂)
//卫语句减少嵌套
public String getUserAddressArea(User user) {
if (user == null) {
return null;
}
if (user.getAddress() == null) {
return null;
}
return user.getAddress().getArea();
}
java8提供了Optional更优雅的方式应对上述问题
//使用Optional避免NPE
public String getUserAddressArea(User user) {
return Optional.ofNullable(user)
.map(u -> u.getAddress())
.map(address -> address.getArea())
.orElseGet(() -> null);
}
//附加其它条件
public static String getUserAddressArea(User user) {
return Optional.ofNullable(user)
.filter(u -> "yueming".equals(u.getName()))
.map(u -> u.getAddress())
.map(address -> address.getArea())
.orElseGet(() -> null);
}
上面就是Optional的基本用法,下面简单介绍一下里面用到的一些方法(具体请参照官方的API文档)
常用方法
- Optional对象构建方法(因为其构造函数是private的因此提供了静态方法来构建Optional对象)
- public static <T> Optional<T> of(T value)
- public static <T> Optional<T> ofNullable(T value)
- public static<T> Optional<T> empty()
前两个方法的区别在于第一个方法如果参数为value为null会抛出NPE,一般比较少使用,第二个方法则会返回一个空的Optional对象(调用的就是第三个方法)。传入的值可以使用get方法获取。
- map和flatMap方法,两者的作用一样表示如果存在值则通过提供的映射函数返回一个Optional对象最终的值可由get()方法获取。两者的区别在于参数不一样,flatMap需要传入一个Optional的映射方法。
- public<U> Optional<U> map(Function<? super T, ? extends U> mapper)
- public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper)
// 使用flatMap
public static String getUserAddressArea(User user) {
return Optional.ofNullable(user)
.filter(u -> "yueming".equals(u.getName()))
.flatMap(u -> u.getAddress())
.map(address -> address.getArea())
.orElseGet(() -> null);
}
//User 类中的getAddress方法
public Optional<Address> getAddress() {
return Optional.ofNullable(address);
}
//使用map
public static String getUserAddressArea(User user) {
return Optional.ofNullable(user)
.filter(u -> "yueming".equals(u.getName()))
.map(u -> u.getAddress())
.map(address -> address.getArea())
.orElseGet(() -> null);
}
// User 类中的getAddress方法
public Address getAddress() {
return address;
}
- isPresent 和 ifPresent
- public boolean isPresent() 判断值是否为null返回true或false,map和flatMap方法调用了此方法来判断值是否为空
- public void ifPresent(Consumer<? super T> consumer) 如果值不为null则执行consumer传入的操作
- orElse和orElseGet,orElseThrow三者的作用均是判断值是否为空然后返回区别在于其参数类型不一样,如果值不为空则返回值否则返回的结果由参数获取(具体可参见源代码)。
- public T orElse(T other)
- public T orElseGet(Supplier<? extends T> other)
- public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)
- filter 谓词匹配
Optional原理
原理其实很简单就是把要处理的对象传入Optional,本来应该由用户来判断的是否为null的逻辑封装起来了而已(将经常用到的逻辑封装起来复用代码让代码更加优雅),可自行查看Optional源代码了解。
public final class Optional<T> {
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
// 构造Optional
private Optional() {
this.value = null;
}
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() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
//判断是否为空 核心还是判断是不是为null,filter,map,flatMap方法均有调用isPresent
//其它orElse、orElseGet、orElseThrow、ifPresent、get方法也均是采用了value != null来做判断。
public boolean isPresent() {
return value != null;
}
...
}