【java】Optional,沉浸式开发

在没有optional之前,我们很多时候都是使用if-else-if来进行条件判断,然后根据条件来获取对应数据。例如:获取赵一所在的职位名称。

List<Expert> experts = Arrays.asList(
                new Expert("jiashn","男",20,new Position("总经理",1)),
                new Expert("张三","女",21,new Position("财务总监",2)),
                new Expert("王五","女",26,new Position("会计",3)),
                new Expert("李四","男",24,new Position("开发部经理",2))
        );
//获取赵一所在的职位名称
if(CollectionUtils.isNotEmpty(experts)){
    for (Expert expert : experts) {
        if (Objects.equals("赵一",expert.getName())){
            Position position = expert.getPosition();
            if (Objects.nonNull(position)){
                System.out.println(position.getName());
            }
        }
    }
}

使用optional就会优雅很多,也会尽量的避免NPE。如:

String name = Optional.of(users.stream().filter(user -> Objects.equals("赵一", user.getName())).findFirst())
                .get()
                .map(SystemUser::getPosition)
                .map(Position::getName)
                .orElse("");
        System.out.println("Optional获取职位名称:" + name);

上述代码对比中,我们可以清晰感觉到使用optional代码比较优雅,也没有大量代码判空,即使数据不存在也没报NPE。
Optional是JDK1.8后引入的一个新特性,通常被认为是用于缓解java中NPE问题。Optional作为容器,可以保存类型T的值,也可以直接保存null。

Optional方法

准备工作,创建一个有数据的系统用户,一个为null的数据。

/**
 * @author: jiangjs
 * @description: 系统用户
 * @date: 2023/5/8 11:40
 **/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class SystemUser {
    private String name;
    private String gender;
    private Integer age;
    private Position position;

    public Optional<Position> optionalPosition(){
        return Optional.ofNullable(position);
    }
}

/**
 * @author: jiangjs
 * @description: 职位
 * @date: 2023/5/8 11:20
 **/
@Data
@AllArgsConstructor
public class Position {

    /**
     * 职位名称
     */
    private String name;
    /**
     * 职位等级
     */
    private Integer level;

}
 SystemUser systemUser = new SystemUser("王五","女",26,new Position("会计",3));
 SystemUser user = null;

empty

static<T> Optional<T> empty():静态方法,返回空的Optional。
源码:

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

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

实现:

//empty
Object o = Optional.empty();
System.out.println("empty:" + o);

输出:

💡 empty:Optional.empty

of、ofNullable

static <T> Optional<T> of(T value):创建一个非空的Optional。
static <T> Optional<T> ofNullable(T value):如果T不为空,则创建指定值的Optional,否则返回空的Optional。

//of ofNullable
Optional<SystemUser> systemUserOptional = Optional.of(systemUser);
System.out.println("systemUserOptional:" + systemUserOptional);

Optional<SystemUser> userOptional = Optional.of(user);
System.out.println("userOptional:" + userOptional);

Optional<SystemUser> optionalSystemUser = Optional.ofNullable(systemUser);
System.out.println("optionalSystemUser:" + optionalSystemUser);

Optional<SystemUser> optionalUser = Optional.ofNullable(user);
System.out.println("optionalUser:" + optionalUser);

输出:

💡 systemUserOptional:Optional[SystemUser(name=王五, gender=女, age=26, position=Position(name=会计, level=3))]

💡 java.lang.NullPointerException

💡 optionalSystemUser:Optional[SystemUser(name=王五, gender=女, age=26, position=Position(name=会计, level=3))]

💡 optionalUser:Optional.empty

Optional.of(user):报了空指针异常,这是因为of在创建Optional时,会对T进行判空处理。

public static <T> Optional<T> of(T value) {
    return new Optional<>(value);
}

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

Optional.ofNullable(user):使用了三目运算符,如果T为空,则调用empty(),返回空的Optional。

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

isPresent()

isPresent():判断是否包含指定值,包含返回true,反之返回false。

//isPresent
boolean present = Optional.of(systemUser).isPresent();
System.out.println("systemUser是否存在:" + present);

boolean judge = Optional.ofNullable(user).isPresent();
System.out.println("user是否存在:" + judge);

输出:

💡 systemUser是否存在:true
💡 user是否存在:false

isPresent():直接获取Optional中的T来判空。

 public boolean isPresent() {
    return value != null;
}

注:在写代码时,不要即用了if,又用isPresent来进行判断,如:if (Optional.ofNullable(user).isPresent()){业务代码},这样消除不了繁琐的if判断,也创建了Optional对象。

orElse、orElseGet

T orElseGet(Supplier<? extends T> other):如果调用对象包含值,则返回该值,否则返回other。
T orElse(T other):如果调用对象包含值,则返回该值,否则返回other。

//orElseGet,orElse
SystemUser orElseGetUser = Optional.ofNullable(user).orElseGet(UseOptional::getSystemUser);
System.out.println("orElseGetUser:" + orElseGetUser);
SystemUser orElseUser = Optional.ofNullable(user).orElse(getSystemUser());
System.out.println("orElseUser:" + orElseUser);

SystemUser orElseGetSystemUser = Optional.of(systemUser).orElseGet(UseOptional::getSystemUser);
System.out.println("orElseGetSystemUser:" + orElseGetSystemUser);
SystemUser orElseSystemUser = Optional.of(systemUser).orElse(getSystemUser());
System.out.println("orElseSystemUser:" + orElseSystemUser);

输出:

默认数据:SystemUser(name=李四, gender=男, age=24, position=Position(name=开发部经理, level=2))
💡 orElseGetUser:SystemUser(name=李四, gender=男, age=24, position=Position(name=开发部经理, level=2))
默认数据:SystemUser(name=李四, gender=男, age=24, position=Position(name=开发部经理, level=2))
💡 orElseUser:SystemUser(name=李四, gender=男, age=24, position=Position(name=开发部经理, level=2))

💡 orElseGetSystemUser:SystemUser(name=王五, gender=女, age=26,
position=Position(name=会计, level=3)) 默认数据:SystemUser(name=李四,
gender=男, age=24, position=Position(name=开发部经理, level=2))
💡 orElseSystemUser:SystemUser(name=王五, gender=女, age=26,
position=Position(name=会计, level=3))

当调用对象不包含值是,虽然两者都是返回other,但是从定义中我们可以看到orElseGet是使用了Supplier函数式编程,而orElse直接使用T。上面例子也说明了orElse会提前创建T而orElseGet会在判断调用对象没有时才会调用Supplier来创建other。

orElse与orElseGet区别

💡 orElse:不管调用对象是否存在,都会提前创建T。 💡
orElseGet:只有当调用对象不存在时,才会使用Supplier创建返回值。

get

get():即获取Optional的对象数据,如果对象数据不存在则抛出异常:NoSuchElementException

//get
SystemUser getSystemUser = Optional.ofNullable(systemUser).get();
System.out.println("getSystemUser:" + getSystemUser);
SystemUser getUser = Optional.ofNullable(user).get();
System.out.println("getUser:" + getUser);

输出:

💡 getSystemUser:SystemUser(name=王五, gender=女, age=26,
position=Position(name=会计, level=3))
💡 Exception in thread "main"java.util.NoSuchElementException: No value present at java.util.Optional.get(Optional.java:135) at com.jiashn.springbootproject.useUtil.UseOptional.main(UseOptional.java:86)

map、flatMap

<U> Optional<U> map(Function<? super T, ? extends U> mapper):如果有值,则进行数据处理,如果没有值,则返回Optional.empty()。
<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper):与map类似,要求返回值必须是Optional。

//map
String sysUserName = Optional.of(systemUser).map(SystemUser::getName).get();
System.out.println("sysUserName:" + sysUserName);
Optional<String> userName = Optional.ofNullable(user).map(SystemUser::getName);
System.out.println("userName:" + userName);
//flatMap
String name = Optional.of(systemUser)
        .flatMap(SystemUser::optionalPosition)
        .map(Position::getName).get();
System.out.println("name:" + name);

输出:

💡 sysUserName:王五
💡 userName:Optional.empty
💡 name:会计

jdk引入了Optional能让我们快捷的获取比较复杂的数据结构中的数据,同时也能有效避免NPE,当然Optional方法单独使用可能效果不大,但是组合使用时会让我们事半功倍。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值