问题描述
我正在阅读有关 Java 流的信息,并在学习过程中发现新事物.我发现的新事物之一是 peek()
函数.我在 peek 上读到的几乎所有内容都说它应该用于调试您的 Streams.
I'm reading up about Java streams and discovering new things as I go along. One of the new things I found was the peek()
function. Almost everything I've read on peek says it should be used to debug your Streams.
如果我有一个流,其中每个帐户都有一个用户名、密码字段和一个 login() 和 login() 方法.
What if I had a Stream where each Account has a username, password field and a login() and loggedIn() method.
我也有
Consumer<Account> login = account -> account.login();
和
Predicate<Account> loggedIn = account -> account.loggedIn();
为什么会这么糟糕?
List<Account> accounts; //assume it's been setup
List<Account> loggedInAccount =
accounts.stream()
.peek(login)
.filter(loggedIn)
.collect(Collectors.toList());
据我所知,这完全符合它的意图.它;
Now as far as I can tell this does exactly what it's intended to do. It;
- 获取帐户列表
- 尝试登录每个帐户
- 过滤掉所有未登录的帐户
- 将登录的帐户收集到一个新列表中
这样做的缺点是什么?有什么理由我不应该继续?最后,如果不是这个解决方案,那又是什么?
What is the downside of doing something like this? Any reason I shouldn't proceed? Lastly, if not this solution then what?
这个的原始版本使用了 .filter() 方法如下;
The original version of this used the .filter() method as follows;
.filter(account -> {
account.login();
return account.loggedIn();
})
推荐答案
关键要点:
不要以无意的方式使用 API,即使它可以实现您的近期目标.这种方法在未来可能会失效,而且未来的维护者也不清楚.
Don't use the API in an unintended way, even if it accomplishes your immediate goal. That approach may break in the future, and it is also unclear to future maintainers.
将其分解为多个操作没有坏处,因为它们是不同的操作.以不明确和意外的方式使用 API 存在危害,如果在 Java 的未来版本中修改此特定行为,则可能会产生后果.
There is no harm in breaking this out to multiple operations, as they are distinct operations. There is harm in using the API in an unclear and unintended way, which may have ramifications if this particular behavior is modified in future versions of Java.
在此操作上使用 forEach
将使维护者清楚,accounts
的每个元素都有预期的副作用,并且你正在执行一些可以改变它的操作.
Using forEach
on this operation would make it clear to the maintainer that there is an intended side effect on each element of accounts
, and that you are performing some operation that can mutate it.
从某种意义上说,peek
是一个中间操作,它在终端操作运行之前不会对整个集合进行操作,这也更传统,但 forEach
确实是一个终端操作.通过这种方式,您可以围绕代码的行为和流程提出强有力的论据,而不是询问 peek
在此上下文中的行为是否与 forEach
的行为相同.
It's also more conventional in the sense that peek
is an intermediate operation which doesn't operate on the entire collection until the terminal operation runs, but forEach
is indeed a terminal operation. This way, you can make strong arguments around the behavior and the flow of your code as opposed to asking questions about if peek
would behave the same as forEach
does in this context.
accounts.forEach(a -> a.login());
List<Account> loggedInAccounts = accounts.stream()
.filter(Account::loggedIn)
.collect(Collectors.toList());
这篇关于在 Java 流中,peek 真的只用于调试吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!