【发布时间】:2016-02-11 16:02:45
【问题描述】:
我正在阅读有关 Java 流的信息,并在此过程中发现新事物。我发现的新事物之一是peek() 函数。我在 peek 上读到的几乎所有内容都表明它应该用于调试您的 Streams。
如果我有一个 Stream,其中每个 Account 都有一个用户名、密码字段和一个 login() 和 loggedIn() 方法。
我也有
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());
现在据我所知,这完全符合它的预期。它;
- 获取帐户列表
- 尝试登录每个帐户
- 过滤掉任何未登录的帐户
- 将登录的帐户收集到一个新列表中
做这样的事情有什么坏处?有什么理由我不应该继续?最后,如果不是这个解决方案,那又是什么?
这个原始版本使用.filter()方法如下;
.filter(account -> {
account.login();
return account.loggedIn();
})
【问题讨论】:
-
每当我发现自己需要多行 lambda 时,我都会将这些行移至私有方法并传递方法引用而不是 lambda。
-
目的是什么 - 您是否尝试在中记录所有帐户并根据它们是否已登录来过滤它们(这可能是微不足道的)?或者,您是否要让他们登录,然后根据他们是否登录来过滤他们?我按这个顺序问这个问题是因为
forEach可能是您想要的操作,而不是peek。仅仅因为它在 API 中并不意味着它不会被滥用(例如Optional.of)。 -
另请注意,您的代码可能只是
.peek(Account::login)和.filter(Account::loggedIn);没有理由编写只调用另一个类似方法的消费者和谓词。 -
还要注意行为参数中的流APIexplicitly discourages side-effects。
-
有用的消费者总是有副作用,当然不会气馁。这实际上在同一节中提到:“少量流操作,例如
forEach()和peek(),只能通过副作用进行操作;这些应该小心使用。”。我的评论更多的是提醒peek操作(它是为调试目的而设计的)不应该被在另一个操作中做同样的事情来代替,比如map()或filter()。
标签: java java-8 java-stream peek