一尘不染

在Java流中,peek真的仅用于调试吗?

java

我正在阅读有关Java流的信息,并在不断学习中发现新事物。我发现的新peek()功能之一就是功能。我偷看的几乎所有内容都说应将其用于调试Streams。

如果我有一个Stream,其中每个帐户都有一个用户名,密码字段以及一个login()和loggingIn()方法,该怎么办。

我也有

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();
    })

阅读 613

收藏
2020-02-28

共1个答案

一尘不染

关键要点是:

即使达到你的近期目标,也不要以意外的方式使用该API。这种方法将来可能会中断,对于将来的维护者来说也不清楚。

将其分解为多个操作是没有害处的,因为它们是不同的操作。还有就是在不明确的和意想不到的方式,如果这种特定的行为是用Java的未来版本中修改其可能的后果使用API的伤害。

使用forEach该操作将明确维护者,有一个预期中的每个元素的副作用accounts,并且正在执行某些操作,可能发生变异它。

从某种意义上说,它是更常规peek的中间操作,直到终端操作运行后才对整个集合进行操作,但forEach实际上是终端操作。这样,你可以围绕代码的行为和流程提出强有力的论据,而不是询问是否peek行为与forEach在此情况下相同。

accounts.forEach(a -> a.login());
List<Account> loggedInAccounts = accounts.stream()
                                         .filter(Account::loggedIn)
                                         .collect(Collectors.toList());
2020-02-28