试图将嵌套的for循环表示为Java流,但感到困惑
我试图更好地理解java中的流,我只是试图将嵌套的for循环表示为流,但我很难理解它 我试过几件事,但似乎都抓不住 例如,类似这样的事情试图将嵌套的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); } } }
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
。