<阿里Java开发手册>提到过一点"防止NPE,是程序员的基本修养
- NPE:Null Pointer Exception, 可能是基本上是最常见的一种异常类型, 同时也是最容易忽视的异常! 实际开发中,这个问题很容易就可以发生, 一发生可能就得重新打包上线(
比较常见的几个行为: 强制转换, 数据库查询返回null, Session取数据
)
举例 代码
//此时如果user 为 null, 则出 空指针异常
user.getArea().getName();
改进
//但是这种写法并不优雅(if 地狱),为了避免这种情况, Java8 提供了Optional类!
if(user != null){
user.getArea().getName();
}
解析
1. Optional(T value),empty(),of(T value),ofNullable(T value)
of(T value)
Optional(T value)是private权限, 不可外部调用.其余为public权限.故其本质为内部存储了一个真实的值, 在构造期间直接判断是否为空. 创建Optional对象,差别在于of不允许参数是null,而ofNullable则无限制。[下图源码: 摘自网络]
//of(T value) 源码
/**
* Returns an {@code Optional} with the specified present non-null value.
*
* @param <T> the class of the value
* @param value the value to be present, which must be non-null
* @return an {@code Optional} with the value present
* @throws NullPointerException if value is null
*/
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
也就是说of(T value)函数内部调用了构造函数。根据构造函数的源码我们可以得出两个结论:
- 通过of(T value)函数所构造出的Optional对象,当Value值为空时,依然会报NullPointerException。
- 通过of(T value)函数所构造出的Optional对象,当Value值不为空时,能正常构造Optional对象。
除此之外呢,Optional类内部还维护一个value为null的对象,大概就是长下面这样的
/**
* Constructs an empty instance.
*
* @implNote Generally only one empty instance, {@link Optional#EMPTY},
* should exist per VM.
*/
private Optional() {
this.value = null;
}
/**
* Returns an empty {@code Optional} instance. No value is present for this
* Optional.
*
* @apiNote Though it may be tempting to do so, avoid testing if an object
* is empty by comparing with {@code ==} against instances returned by
* {@code Option.empty()}. There is no guarantee that it is a singleton.
* Instead, use {@link #isPresent()}.
*
* @param <T> Type of the non-existent value
* @return an empty {@code Optional}
*/
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
所以: empty()
的作用就是返回EMPTY对象。
ofNullable(T value)作用
源码:
/**
* Returns an {@code Optional} describing the specified value, if non-null,
* otherwise returns an empty {@code Optional}.
*
* @param <T> the class of the value
* @param value the possibly-null value to describe
* @return an {@code Optional} with a present value if the specified value
* is non-null, otherwise an empty {@code Optional}
*/
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
相比较of(T value)
的区别就是,当value值为null时,of(T value)
会报NullPointerException异常;ofNullable(T value)
不会throw Exception,ofNullable(T value)
直接返回一个EMPTY对象。
2.orElse(T other)
,orElseGet(Supplier<? extends T> other)
和orElseThrow(Supplier<? extends X> exceptionSupplier)
这三个函数放一组进行记忆,都是在构造函数传入的value值为null时,进行调用的。orElse和orElseGet的用法如下所示,相当于value值为null时,给予一个默认值:
//这两个函数的区别:
//当user值不为null时,orElse函数依然会执行createUser()方法,而orElseGet函数并不会执行createUser()方法
//至于orElseThrow,就是value值为null时,直接抛一个异常出去,用法如下所示
@Test
public void test() {
User user = null;
user = Optional. ofNullable (user) .orElse (createUser() ) ;
user = Optional. ofNullable (user) .orElseGet( () -> createUser() ) ;
}
public User createUser() {
User user = new User();
user.setName("jianglong") ;
return user;
}
3. map(Function<? super T, ? extends U> mapper)
和flatMap(Function<? super T, Optional<U>> mapper)
源码:
/**
* 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));
}
}
/**
* If a value is present, apply the provided {@code Optional}-bearing
* mapping function to it, return that result, otherwise return an empty
* {@code Optional}. This method is similar to {@link #map(Function)},
* but the provided mapper is one whose result is already an {@code Optional},
* and if invoked, {@code flatMap} does not wrap it with an additional
* {@code Optional}.
*
* @param <U> The type parameter to the {@code Optional} returned by
* @param mapper a mapping function to apply to the value, if present
* the mapping function
* @return the result of applying an {@code Optional}-bearing 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 or returns
* a null result
*/
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));
}
}
这两个函数,在函数体上没什么区别。唯一区别的就是入参,map函数所接受的入参类型为Function<? super T, ? extends U>,而flapMap的入参类型为Function<? super T, Optional<U>>
在具体用法上,对于map而言:
如果User结构是下面这样的
public class User {
private String name;
public String getName() {
return name;
}
}
//取出name
String name = Optional.ofNullable(user).map(u -> u.getName()).get();
4. isPresent()
和ifPresent(Consumer<? super T> consumer)
isPresent即判断value值是否为空,而ifPresent就是在value值不为空时,做一些操作。至于ifPresent(Consumer<? super T> consumer),用法也很简单
Optional.ofNullable(user).ifPressent(u -> {
})
实例: 节选网络上的几个实例
Optional<Integer> optional1 = Optional.ofNullable(1);
Optional<Integer> optional2 = Optional.ofNullable(null);
// isPresent判断值是否存在
System.out.println(optional1.isPresent() == true);
System.out.println(optional2.isPresent() == false);
以前写法:
Java8写法
以前写法:
Java8写法:
以前写法:
Java8写法: