鉴于以下
Function
实现...
从主数据库获取用户凭证
private Function<Long, Optional<UserCredentials>>
getUserCredentialsFromMaster() {
return userId -> Optional.ofNullable(userId)
.flatMap(masterUserRepository::findById)
.map(User::getCredentials);
}
从辅助数据库获取用户凭证
private Function<Long, Optional<UserCredentials>>
getUserCredentialsFromSecondary() {
return userId -> Optional.ofNullable(userId)
.flatMap(secondaryUserRepository::findById)
.map(User::getCredentials);
}
我需要执行
getUserCredentialsFromMaster
或getUserCredentialsFromSecondary
,具体取决于userId
来自哪里。
以下是我的尝试:
考虑域类
UserProfile
public class UserProfile {
Long id;
Long internalUserId; // if internalUserId is null then externalUserId is not
Long externalUserId; // and vice-versa
}
尝试获得
UserCredentials
:
final UserProfile userProfile = userProfileRepository.findById(userProvileId);
final UserCredentials userCredentials =
Optional.ofNullable(userProfile.internalUserId)
.flatMap(getUserCredentialsFromMaster())
.orElse(
Optional.ofNullable(userProfile.externalUserId)
.flatMap(getUserCredentialsFromSecondary())
.orElseThrow(UserCredentialsNotFound::new));
internalUserId
不是 null
但上面的语句总是抛出 UserCredentialsNotFound
。我尝试将 getUserCredentialsFromMaster
和 getUserCredentialsFromSecondary
重写为从 if-then-else 块调用的普通 Java 方法,并且它按预期工作。
我错过了什么吗?
您遇到了异常,因为
Optional.orElse()
的参数被急切地求值。 IE。即使调用它的 Optional
不为空,它也会被评估。
但正如你所说,要么 "
internalUserId
是 null
,然后 externalUserId
不是 null
,反之亦然" 和 orElseThrow()
会产生异常。
首先,请注意
Optional
并不是为执行空检查而设计的。 Optional
的设计目标是充当返回类型,其方法ofNullable()
应该包装一个可为空的返回值,而不是替代null-check。
您可能有兴趣阅读:
隐式空检查并没有什么问题,当代码中有很多空检查时,这有点问题,但它是应用程序中特定行为的实现方式的直接后果,然后问题与该语言提供的工具。
解决此问题的更简洁方法是读取函数并定义一个基于提供的
Supplier
和 id
生成 UserRepository
的方法:
private Supplier<Optional<UserCredentials>> getUserCredentials(Long id, UserRepository repository) {
return id == null ?
Optional::empty :
() -> repository.findById(id).map(User::getCredentials);
}
可以通过以下方式使用:
UserCredentials userCredentials = Stream.of(
getUserCredentials(userProfile.internalUserId, masterUserRepository),
getUserCredentials(userProfile.internalUserId, secondaryUserRepository)
)
.map(Supplier::get)
.flatMap(Optional::stream)
.findFirst()
.orElseThrow(UserCredentialsNotFound::new);
Optional.or()
,它期望 Supplier
为 Optional
,仅在需要时才会对其进行评估。
UserCredentials userCredentials = Optional.ofNullable(userProfile.internalUserId)
.flatMap(getUserCredentialsFromMaster())
.or(() ->
Optional.ofNullable(userProfile.externalUserId)
.flatMap(getUserCredentialsFromSecondary())
)
.orElseThrow(UserCredentialsNotFound::new);
Optional.orElseGet()
,它采用 Supplier
的结果值:
UserCredentials userCredentials = Optional.ofNullable(userProfile.internalUserId)
.flatMap(getUserCredentialsFromMaster())
.orElseGet(() ->
Optional.ofNullable(userProfile.externalUserId)
.flatMap(getUserCredentialsFromSecondary())
.orElseThrow(UserCredentialsNotFound::new)
);