cac*_*co3 7 java lambda optional java-8 java-9
我很好奇,想知道为什么Java的可选没有提供peek类似的方法Stream的一个.
该peek方法的Javadoc所述的Stream界面态:
- @apiNote此方法主要用于支持调试,您希望在元素流经管道中的某个点时查看这些元素
这几乎完全描述了我的用例:
@Override
@Transactional
public User getUserById(long id) {
return repository.findById(id)
.peek(u -> logger.debug("Found user = {} by id = {}", u, id))
.orElseThrow(() -> new UserNotFoundException("id = " + id));
}
Run Code Online (Sandbox Code Playgroud)
(repository.findById返回Optional<User>(参见CrudRepository#findById))
但由于没有peek方法,因此无法编译Optional.
因此,如果没有peek方法,以上所有内容都将转换
@Override
@Transactional
public User getUserById(long id) {
Optional<User> userOptional = repository.findById(id);
if (userOptional.isPresent()) {
logger.debug("Found user = {} with id = {}", userOptional.get(), id);
}
return userOptional.orElseThrow(() -> new UserNotFoundException("id = " + id));
}
Run Code Online (Sandbox Code Playgroud)
也可以这样做(见这个答案):
@NoArgsConstructor(access = PRIVATE)
public abstract class OptionalUtils {
public static <T> UnaryOperator<T> peek(Consumer<T> consumer) {
return t -> {
consumer.accept(t);
return t;
};
}
}
Run Code Online (Sandbox Code Playgroud)
并使用它与map方法:
return repository.findById(id)
.map(OptionalUtils.peek(u -> logger.debug("Found user = {} with id = {}", u, id)))
.orElseThrow(() -> new UserNotFoundException("id = " + id));
Run Code Online (Sandbox Code Playgroud)
但我认为这是一个黑客而不是干净利用Optional.
从Java 9开始,可以转换Optional为Stream但流不具备该orElseThrow方法(显然它不应该).
也可以使用相同ifPresent但返回void.(对我来说似乎不ifPresent应该返回任何其他东西void)
我在滥用Optional吗?
这种peek方法的缺失是故意的吗?(但与此同时,Vavr Option确实提供了这种peek方法.)
或者它被认为不值得吗?
已经有Optional::ifPresent接受a 的方法了Consumer.
在Java 8中,唯一的方法是使用Optional::map,将实体映射到自身并将其用作peek方法:
return repository.findById(id)
.map(u -> {
logger.debug("Found user = {} with id = {}", u, id)
return u;
})
.orElseThrow(() -> new UserNotFoundException("id = " + id));
Run Code Online (Sandbox Code Playgroud)
......应简化实施自己的peek方法:
<T> UnaryOperator<T> peek(Consumer<T> consumer) {
return t -> {
consumer.accept(t);
return t;
};
}
Run Code Online (Sandbox Code Playgroud)
......并且舒适地使用Optional:
return repository.findById(id)
.map(this.peek(logger.debug("Found user = {} with id = {}", u, id)))
.orElseThrow(() -> new UserNotFoundException("id = " + id));
Run Code Online (Sandbox Code Playgroud)
好吧,只有设计者才能回答你“确切”的细节,为什么Optional 没有 peek 方法。
所以,现在,你不得不使用isPresent()在我看来实际上看起来很好的方法:
if (userOptional.isPresent())
logger.debug("Found user = {} with id = {}", userOptional.get(), id);
Run Code Online (Sandbox Code Playgroud)
或者,如果您希望将其作为管道的一部分,您可以考虑链接页面上的建议答案。
顺便说一句,考虑到 JDK9 的新stream方法,你可以这样做:
return repository.findById(id) // Optional<User>
.stream() // Stream<User>
.peek(u -> logger.debug("Found user = {} by id = {}", u, id)) // Stream<User>
.findFirst() // Optional<User>
.orElseThrow(() -> new UserNotFoundException("id = " + id))
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
481 次 |
| 最近记录: |