如何将代码重写为选项?

max*_*ver 17 java nullpointerexception optional java-8

在我目前的工作中,我们将一些代码重写为Java 8.如果你有这样的代码:

if(getApi() != null && getApi().getUser() != null 
     && getApi().getUser().getCurrentTask() != null)  
{
   getApi().getUser().getCurrentTask().pause();
}
Run Code Online (Sandbox Code Playgroud)

你可以简单地重写它

Optional.ofNullable(this.getApi())
.map(Api::getUser)
.map(User::getCurrentTask)
.ifPresent(Task::pause);
Run Code Online (Sandbox Code Playgroud)

不改变代码行为.但是,如果中间的东西可以抛出NPE,因为它没有被检查为空呢?

例如:

if(getApi() != null && getApi().getUser() != null 
     && getApi().hasTasks())  
{
   getApi().getMasterUser(getApi().getUser()) //<- npe can be here
     .getCurrentTask().pause();
}
Run Code Online (Sandbox Code Playgroud)

使用optionals重写这样的代码的最佳方法是什么?(它应该完全相同,并在getMasterUser(...)返回null 时抛出npe )

UPD 第二个例子:

if(getApi()!=null && getApi.getUser() != null)
{
   if(getApi().getUser().getDepartment().getBoss() != null)// <- nre if department is null
     {
        getApi().getUser().getDepartment().getBoss().somefunc();
     }
 }
Run Code Online (Sandbox Code Playgroud)

它有api,用户,老板的零检查,但不是部门.怎么用选项?

fgb*_*fgb 7

if(getApi() != null && getApi().getUser() != null) {
    if(getApi().getUser().getDepartment().getBoss() != null) {
        getApi().getUser().getDepartment().getBoss().somefunc();
    }
}
Run Code Online (Sandbox Code Playgroud)

用选项写这个的一种方法是:

Optional.ofNullable(this.getApi())
    .map(Api::getUser)
    .map(user -> Objects.requireNonNull(user.getDepartment()))
    .map(Department::getBoss)
    .ifPresent(Boss::somefunc);
Run Code Online (Sandbox Code Playgroud)

但这很容易出错,因为它要求客户端跟踪什么是可选的,哪些不是可选的.更好的方法是使api本身返回一个可选而不是可为空的值.然后客户端代码是:

this.getApi()
    .flatMap(Api::getUser)
    .map(user -> user.getDepartment().getBoss())
    .ifPresent(Boss::somefunc));
Run Code Online (Sandbox Code Playgroud)

这将使api更清晰,哪些值应该是可选的,并使其成为编译时错误,以便不处理它们.

if(getApi() != null && getApi().getUser() != null && getApi().hasTasks()) {
    getApi().getMasterUser(getApi().getUser()).getCurrentTask().pause();
}
Run Code Online (Sandbox Code Playgroud)

在这里,你需要访问api,并user在同一时间,所以你可能需要嵌套lambda表达式:

getApi().filter(Api::hasTasks).ifPresent(api -> {
    api.getUser().ifPresent(user -> {
        api.getMasterUser(user).getCurrentTask().ifPresent(Task::pause);
    });
});
Run Code Online (Sandbox Code Playgroud)