[英]Is this example of use Optionals in java 8 correct? How would you rewrite it?
[英]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();
}
在這里,您需要同時訪問api
和user
,因此您可能需要嵌套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.