首页 > 编程语言 >Java11 Optional

Java11 Optional

时间:2023-06-11 22:24:52浏览次数:43  
标签:return userId value userInfo Java11 Optional public

简介

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 

标签:return,userId,value,userInfo,Java11,Optional,public
From: https://www.cnblogs.com/52-IT-y/p/17473136.html

相关文章

  • idea中jdk11用maven编译失败 Fatal error compiling: tools.jar not found: XX\Java
    ideamaven编译需要用到jdk的lib包里面的tools.jar文件,但是jdk1.8之后就没有tools.jar了。我这里用的是graalvm的jdk11,编译一直报错,网上也查不到。解决办法: 根据对应路径创建一个lib包,并把jdk1.8的lib下面的tools.jar复制一个放到这个包下面,让这个路径有这个包就行了。我......
  • 学习笔记-Java8新特性-第五节-Optional类
    Optional类Optional<T>是一个容器类代表一个值存在或不存在致力于解决空指针异常问题(NPE)可以快速锁定发生NPE的位置(这东西真的好用吗?)常用方法Optional.of(Tt)创建一个Optional实例不能传入空指针,会报NPE使用Optional,报空指针了,说明就是这里的问题?......
  • Optional对象的使用
    Optional是一个对象容器,具有以下两个特点:提示用户要注意该对象有可能为null简化ifelse代码1.创建:Optional.empty():创建一个空的Optional实例//返回一个Null的optionalOptionalempty=Optional.empty();Optional.of(Tt):创建一个Optional......
  • Windows11实现java8和java11自由切换
    由于运行不同的软件需要不同的java版本,因此需要不时切换java环境。以下基于win11实现java8和java11环境自由切换。第一步:安装jdk8和jdk11傻瓜式安装,点击下一步即可。需要记住安装路径。安装完成后如图所示:第二步:将jdk8和jdk11安装路径添加至系统变量新建两个系统变量,指定jav......
  • Java8更新Java11, 修复使java11环境生效
     原因:jenkins安装新版本时发现不支持java8了,需要手动删除旧的8更新到11,再配置环境变量.报错:jenkins:invalidJavaversion:openjdkversion"1.8.0_312" 1.先卸载旧的java8dnfremovejava 2.安装装版本java11yuminstall-yfontconfigjava-11-openjdkjava-1......
  • Java8新特性6_Optional容器类
    Optional类概念Optional类是一个容器类,代表一个值存在或者不存在,原来null表示一个值不存在,现在Optional可以更好的表达这个概念,并且可以规避空指针异常常用方法Optional.of:创建一个Optional实例Optional.empty:创建一个空的Optional实例Optional.ofNullable:若t不为null......
  • java Optional使用
    1.Optional.of()或者Optional.ofNullable()创建Optional对象,差别在于of不允许参数是null,而ofNullable则无限制。1//参数不能是null2Optional<Integer>optional1=Optional.of(1);34//参数可以是null5Optional<Integer>optional2=Optional.ofNullable(null);2......
  • java11_Object类
    Object类相关JavaObject类是所有类的父类,也就是说Java的所有类都继承了Object,子类可以使用Object的所有方法。Object类位于java.lang包中,编译时会自动导入,我们创建一个类时,如果没有明确继承一个父类,那么它就会自动继承Object,成为Object的子类。内部结构:类的......
  • C++17:新特性之std::optional
    考虑一个问题,C++如何实现返回多个值?如何标记其中一个bool返回值用于记录函数运行状态?我们可以通过pair或tuple实现,有以下代码:#include<iostream>#include<string>usingnamespacestd;structss{ strings; intsize;};pair<bool,ss>func2(conststring&in){......
  • 使用Optional优雅避免空指针异常
    本文已收录至Github,推荐阅读......