簡體   English   中英

如何將代碼重寫為選項?

[英]How to rewrite code to optionals?

在我目前的工作中,我們將一些代碼重寫為Java 8.如果你有這樣的代碼:

if(getApi() != null && getApi().getUser() != null 
     && getApi().getUser().getCurrentTask() != null)  
{
   getApi().getUser().getCurrentTask().pause();
}

你可以簡單地重寫它

Optional.ofNullable(this.getApi())
.map(Api::getUser)
.map(User::getCurrentTask)
.ifPresent(Task::pause);

不改變代碼行為。 但是,如果中間的東西可以拋出NPE,因為它沒有被檢查為空呢?

例如:

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

使用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();
     }
 }

它有api,用戶,老板的零檢查,但不是部門。 怎么用選項?

if(getApi() != null && getApi().getUser() != null) {
    if(getApi().getUser().getDepartment().getBoss() != null) {
        getApi().getUser().getDepartment().getBoss().somefunc();
    }
}

用選項寫這個的一種方法是:

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

但這很容易出錯,因為它要求客戶端跟蹤什么是可選的,哪些不是可選的。 更好的方法是使api本身返回一個可選而不是可為空的值。 然后客戶端代碼是:

this.getApi()
    .flatMap(Api::getUser)
    .map(user -> user.getDepartment().getBoss())
    .ifPresent(Boss::somefunc));

這將使api更清晰,哪些值應該是可選的,並使其成為編譯時錯誤,以便不處理它們。

if(getApi() != null && getApi().getUser() != null && getApi().hasTasks()) {
    getApi().getMasterUser(getApi().getUser()).getCurrentTask().pause();
}

在這里,您需要同時訪問apiuser ,因此您可能需要嵌套lambdas:

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

對於第二個示例(也適用於第一個示例),這更短,並且與更長的版本一樣明顯:

Optional.ofNullable(getApi())
.map(Api::getUser)
.flatMap(u -> Optional.ofNullable(u.getDepartment().getBoss()))
.ifPresent(Boss::somefunc);

它還依賴於較少的API。

我還想評論你的“這打破monad模式” - 這里沒有任何東西(包括你的解決方案)打破monad模式。 它在return>>=方面完全可以表達。 如果有的話,那就是ifPresent調用打破了它,因為它暗示了副作用。

所以第一個例子的答案是

Optional.ofNullable(getApi())
.filter(Api::hasTasks)
.map(Api::getUser)
.map(u -> Objects.requireNonNull(getApi().getMasterUser(u)))//api won't be null here so no need to check it
.map(MasterUser::getCurrentTask)
.ifPresent(Task::pause);

第二個例子:

Optional.ofNullable(getApi())
.map(Api::getUser)
.map(u -> Objects.requireNonNull(u.getDepartment()))
.map(Department::getBoss)
.ifPresent(Boss::somefunc);

所以你必須將.map(class::func)更改為.map(o -> Objects.requireNonNull(o.func()))以使其在需要時拋出NRE。

它當然打破了monad模式,但它仍然比沒有任何解決方案更好

如果我錯了,請糾正我。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM