试图将嵌套的for循环表示为Java流,但感到困惑

试图将嵌套的for循环表示为Java流,但感到困惑,java,java-stream,Java,Java Stream,我试图更好地理解java中的流,我只是试图将嵌套的for循环表示为流,但我很难理解它 我试过几件事,但似乎都抓不住 例如,类似这样的事情 for (Profile profile : profiles) { for (User user : users) { if (user.getUserId().equals(profile.getProfileId())) { profile.setField(false); } } }

我试图更好地理解java中的流,我只是试图将嵌套的for循环表示为流,但我很难理解它

我试过几件事,但似乎都抓不住

例如,类似这样的事情

for (Profile profile : profiles) {
    for (User user : users) {
        if (user.getUserId().equals(profile.getProfileId())) {
           profile.setField(false);
        }
    }
}

作为Java中的流,您将如何做到这一点?

我认为您正在试图理解流,但让我说,版本的
并没有更差,
流的
版本也没有更好:性能测试和直觉可能会帮助您做到这一点,以及可读性

也就是说,您的问题在于,您的第二个外观需要第一个外观才能工作:

profiles.stream()
        .filter(profile -> users.stream() 
                                .anyMatch(user -> user.getUserId().equals(profile.getProfileId())))
        .forEach(profile -> profile.setField(false));
  
这与for循环完全不同:您可以对每个配置文件调用几次
setField
,而在流版本中,只有在有一个匹配用户的情况下才会调用。我假设
setField
是一个setter,同样地,由于它的值是常量,所以调用一次或多次都不重要

在这种情况下,我建议您不要使用第一个流,或者将自己限制为
forEach

profiles.forEach(profile -> profile.setField(!users.stream() 
                                   .anyMatch(user -> user.getUserId().equals(profile.getProfileId())));
可以通过首先获取所有用户ID并使用生成集的contains来简化:

   var userIds = users.stream().map(User::getUserId).collect(toSet());
   profiles.forEach(profile -> profile.setField(!userIds.contains(profile.getProfileId()));

这个特定的示例根本没有从流中受益,可以归结为对
forEach
的嵌套调用,这些调用看起来几乎与原始调用完全相同。由于您在两个不相关的集合上进行迭代,因此流在这里不能真正使用
anyMatch
与上次匹配的不一样,这可能是一个不兼容的更改。另一个注意事项是,为什么要假设在使用所讨论的文件时,将
id
=
进行比较?您的上一个代码还将某些配置文件的
字段
属性设置为
true
,这与现有的代码行为不兼容。这是一个逻辑和惰性问题:这里的逻辑是读取
for*2
版本,如果有匹配的用户,则调用
profile.setField(false)
。我希望该方法是一个简单的setter:如果它计算调用数,这将是真正不同的,但我宁愿为它选择一个更好的名称。至于
user.id==profile.id
,正如我所说,我出于懒惰简化了getter,所以是的,它应该是
user.getUserId().equals(profile.getProfileId())
。简化getter并不意味着你不能比较
user.id.equals(profile.id)
。我不是在说电话数。只需在样本数据上测试您的方法和有问题的方法,其中一些配置文件不在选中的
userid
下,但先前为
字段
属性分配了值
false