Java11 Optional
简介
public final class Optional<T> {
private static final Optional<?> EMPTY = new Optional<>();
private final T value;
private Optional() {
this.value = null;
}
……
}
Optional<T> 是个容器,在java.util包中用保存类型T的值或者保存null的工具类。Optional<T> 类的引入很好的解决空指针异常
Optional类设计意图:
- Optional 尽量用作为方法的返回值
- Optional 清晰的表达返回值是没有值的可能性,并且如果直接返回 null 可能会导致调用端出现空指针异常
构造 Optional<T> 方法
Optional.of(T value)
public static <T> Optional<T> of(T value) {
return new Optional<>(value);
}
Optional.of(T value)
该方法通过一个非 null 的 value 来构造一个 Optional,返回的 Optional 包含 value 这个值
- 传入的参数一定不能为 null,否则便会抛出
NullPointerException
Optional.empty()
public static<T> Optional<T> empty() {
@SuppressWarnings("unchecked")
Optional<T> t = (Optional<T>) EMPTY;
return t;
}
Optional.empty()
该方法用来构造一个空的 Optional,即该 Optional 中不包含值
Optional.ofNullable(T value)
public static <T> Optional<T> ofNullable(T value) {
return value == null ? empty() : of(value);
}
Optional.ofNullable(T value)
该方法传入的参数可以为 null 。该方法会判断传入的参数是否为 null,如果为 null 的话,返回 Optional.empty()
Optional<T> 相关方法使用
get()
public T get() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
如果 Optional 中有值,就返回该值,否则抛出异常——确保 Optional 内有值才能调用 get() 方法,结合 isPresent() 方法使用
isPresent()
public boolean isPresent() {
return value != null;
}
如果 Optional 中有值,则返回 true,否者返回 false。常用于检测查询数据返回的实体是否存在。使用实例
public interface UserInfoRepository {
Optional<UserInfo> getUserInfoById(id);
}
Optional<UserInfo> userInfo = getUserInfoById(id);
if(userInfo.isPresent()){
UserInfo info = userInfo.get();
}
ifPresent(Consumer<? super T> consumer)
public void ifPresent(Consumer<? super T> consumer) {
if (value != null)
consumer.accept(value);
}
如果 Optional 中值存在则使用该值调用 consumer , 否则不做任何事情。使用实例
public void saveUserInfo(String userId,String userName,String alias) {
UserInfo userInfo = new UserInfo();
userInfo.setUserId(userId);
userInfo.setUserName(userName);
//别名不为null时设置别名——还不如用三元表达式
Optional.ofNullable(alias).ifPresent(a -> userInfo.setAlias(a));
userInfoRepository.save(userInfo);
}
or(Supplier<? extends Optional<? extends T>> supplier)
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
Objects.requireNonNull(supplier);
if (isPresent()) {
return this;
} else {
@SuppressWarnings("unchecked")
Optional<T> r = (Optional<T>) supplier.get();
return Objects.requireNonNull(r);
}
}
如果一个 Optional 包含值,则返回自己;否则返回由参数 supplier 获得的 Optional。使用实例
public interface UserInfoRepository {
Optional<UserInfo> getUserInfoById(id);
}
public void saveOrUpdateUserInfoName(String userId,String userName) {
UserInfo userInfo = userInfoRepository.getUserInfoById(id).or(()->Optional.of(new UserInfo(userId,userName))).get();
userInfo.setUserName(userName);
userInfoRepository.save(userInfo);
}
orElse(T other)
public T orElse(T other) {
return value != null ? value : other;
}
如果 Optional 中有值则将其返回,否则返回 orElse 方法传入的参数 。使用实例
public interface UserInfoRepository {
Optional<UserInfo> getUserInfoById(id);
}
public void saveOrUpdateUserInfoName(String userId,String userName) {
UserInfo userInfo = userInfoRepository.getUserInfoById(id).orElse(new UserInfo(userId,userName));
userInfo.setUserName(userName);
userInfoRepository.save(userInfo);
}
orElseGet(Supplier<? extends T> other)
public T orElseGet(Supplier<? extends T> other) {
return value != null ? value : other.get();
}
orElseGet 方法传入的参数为一个 Supplier 接口的实现 —— 当 Optional 中有值的时候,返回该值;当 Optional 中没有值的时候,返回从该 Supplier 获得的值。使用实例
public interface UserInfoRepository {
Optional<UserInfo> getUserInfoById(id);
}
public void saveOrUpdateUserInfoName(String userId,String userName) {
UserInfo userInfo = userInfoRepository.getUserInfoById(id).orElseGet(()->{
UserInfo newbie = new UserInfo();
newbie.setUserId(userId);
newbie.setUserName(userName);
newbie.setCreatedAt(LocalDateTime.now());
newbie.setUpdatedAt(LocalDateTime.now());
return newbie;
});
userInfoRepository.save(userInfo);
}
orElseThrow() 和 orElseThrow(Supplier<? extends X> exceptionSupplier)
public T orElseThrow() {
if (value == null) {
throw new NoSuchElementException("No value present");
}
return value;
}
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
if (value != null) {
return value;
} else {
throw exceptionSupplier.get();
}
}
orElseThrow 方法当 Optional 中有值的时候,返回值;没有值的时候会抛出异常,抛出的异常或者抛出自定义的exceptionSupplier 。使用实例
public interface UserInfoRepository {
Optional<UserInfo> findUserInfoByUserId(userId);
}
public UserInfo getUserInfo(String userId) {
Optional<UserInfo> userInfoByUserId = userInfoRepository.findUserInfoByUserId(userId);
return userInfoByUserId.orElseThrow();
}
public UserInfo getUserInfo(String userId) {
Optional<UserInfo> userInfoByUserId = userInfoRepository.findUserInfoByUserId(userId);
return userInfoByUserId.orElseThrow(()->new EntityNotFoundException("userId为 " + userId + " 的用户没有找到"));
}
map(Function<? super T, ? extends U> mapper)
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));
}
}
如果当前 Optional 为 Optional.empty,则依旧返回 Optional.empty;否则返回一个新的 Optional,该 Optional 包含的是函数 mapper 在以 value 作为输入时的输出值。可以多次使用map操作。使用实例
public interface UserInfoRepository {
Optional<UserAddress> getUserInfoById(userId);
}
public UserAddress getUserAddress(String userId){
Optional<UserAddress> userAddress = userInfoRepository.getUserInfoById(userId)
.map(user -> user.getUserAddress());
return userAddress.orElse(new UserAddress());
}
public String getUserPhone(String userId){
Optional<String> phone = userInfoRepository.getUserInfoById(userId)
.map(user -> user.getUserPhone())
.map(phone -> phone.replaceAll("(\\d{3})\\d{4}(\\d{4})","$1****$2"));
return phone.orElse("");
}
flatMap(Function<? super T, ? extends Optional<? extends U>> mapper)
public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent()) {
return empty();
} else {
@SuppressWarnings("unchecked")
Optional<U> r = (Optional<U>) mapper.apply(value);
return Objects.requireNonNull(r);
}
}
flatMap 方法与 map 方法的区别在于,map 方法参数中的函数 mapper 输出的是值,然后 map 方法会使用 Optional.ofNullable 将其包装为 Optional;而 flatMap 要求参数中的函数 mapper 输出的就是 Optional
public interface UserInfoRepository {
Optional<UserAddress> getUserInfoById(userId);
}
public String getUserPhone(String userId){
Optional<String> phone = userInfoRepository.getUserInfoById(userId)
.flatMap(user -> Optional.of(user.getUserPhone()))
.flatMap(phone -> Optional.of(phone.replaceAll("(\\d{3})\\d{4}(\\d{4})","$1****$2")));
return phone.orElse("");
}
filter(Predicate<? super T> predicate)
public Optional<T> filter(Predicate<? super T> predicate) {
Objects.requireNonNull(predicate);
if (!isPresent()) {
return this;
} else {
return predicate.test(value) ? this : empty();
}
}
filter 方法接受一个 Predicate 来对 Optional 中包含的值进行过滤,如果包含的值满足条件,那么还是返回这个 Optional;否则返回 Optional.empty 。使用实例
public interface UserInfoRepository {
Optional<UserInfo> getUserInfoById(userId);
}
public UserAddress getUserAddress(String userId){
Optional<UserAddress> userAddress = userInfoRepository.getUserInfoById(userId)
.filter(user -> user.getStatus() == 1)
.map(user -> user.getUserAddress());
return userAddress.orElse(new UserAddress());
}
ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction)
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
if (value != null) {
action.accept(value);
} else {
emptyAction.run();
}
}
ifPresentOrElse() 方法需要两个参数:一个 action 和一个 emptyAction。如果对象包含值,会执行 action 的动作,否则运行 emptyAction。使用实例
- 如果在有值的时候执行某个动作,或者只是跟踪是否定义了某个值,那么这个方法非常有用
public interface UserInfoRepository {
Optional<UserInfo> getUserInfoById(userId);
}
public void updateUserAddress(String userId,Address address){
userInfoRepository.getUserInfoById(userId)
.ifPresentOrElse((userInfo) -> {
userInfo.setAddress(address);
userInfoRepository.save(userInfo);
},() -> logger.info("userInfo not found"));
}
stream()
public Stream<T> stream() {
if (!isPresent()) {
return Stream.empty();
} else {
return Stream.of(value);
}
}
通过把实例转换为 Stream 对象, 从而调用 Stream API。如果该 Optional 没有值,它会得到空的 Stream,有值的情况下,返回包含这个值的 Stream。使用实例
public interface UserInfoRepository {
Optional<UserInfo> getUserInfoById(userId);
}
public class UserInfoServiceImpl{
@Override
public List<UserInfo> getUserInfoByIds(List<String> userIds){
List<UserInfo> collect = ids.stream()
.map(this::getUserInfoById) // 获得 Stream<Optional<UserInfo>>
.flatMap(Optional::stream) // Stream 的 flatMap 方法将多个流合成一个流
.filter(userInfo -> 1 == userInfo.getStatus())
.collect(Collectors.toList());
}
@Override
public Optional<UserInfo> getUserInfoById(userId){
return userInfoRepository.getUserInfoById(userId);
}
}
总结
- Optional 尽量只用作为方法返回值类型
- 调用了返回值为 Optional 的方法后,一定要做空值检查
- 不要过度使用 Optional 避免降低代码可读性和性能
- 不要给 Optional 变量赋值 null,而应该用 Optional.empty() 表达空值
参考:https://zhuanlan.zhihu.com/p/128481434 、https://zhuanlan.zhihu.com/p/40966718