英文:
Trying to represent a nested for loop as a Java Stream, but confused
问题
我正试图更好地理解 Java 中的流(streams),我只是试图将一个嵌套的 for 循环表示为一个流,但我难以弄清楚。
我尝试了一些方法,但似乎无法掌握。
例如,像这样的一个例子。
for (Profile profile : profiles) {
for (User user : users) {
if (user.getUserId().equals(profile.getProfileId())) {
profile.setField(false);
}
}
}
在 Java 中如何使用流来实现这个呢?
英文:
Im trying to understand streams in java better, and im just trying to represent a nested for loop as a stream but im struggling to figure it out.
Ive tried a handful of things, but I cant seem to grasp it.
For example, something like this.
for (Profile profile : profiles) {
for (User user : users) {
if (user.getUserId().equals(profile.getProfileId())) {
profile.setField(false);
}
}
}
How would one do this as a stream in Java?
答案1
得分: 5
我认为您正在尝试理解流(Stream),但请让我说一下,for
版本并不差,Stream
版本也不一定更好:性能测试和直觉可能会对您有所帮助,以及可读性。
话虽如此,您在这里的问题是,您的第二种方法需要第一种方法才能正常工作:
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())));
英文:
I think you are trying to understand stream, but let me say that the for
version is not worse and the Stream
version is not better: performance test and intuition will probably help you there, as well as readability.
That said, you problem here is that your second look require the first one to work:
profiles.stream()
.filter(profile -> users.stream()
.anyMatch(user -> user.getUserId().equals(profile.getProfileId())))
.forEach(profile -> profile.setField(false));
This is strictly not the same as your for loop: you call setField
several time per profile, while in the stream version it is only ever done if there is one matching user. I assumed that setField
is a setter, and as such since its value is constant, it should not matter if it is called once or several times.
I would advise you not to use the first stream in this case, or limit yourself to forEach
:
profiles.forEach(profile -> profile.setField(!users.stream()
.anyMatch(user -> user.getUserId().equals(profile.getProfileId())));
Which could be simplified by first getting all user ids and using contains from the generated set:
var userIds = users.stream().map(User::getUserId).collect(toSet());
profiles.forEach(profile -> profile.setField(!userIds.contains(profile.getProfileId()));
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论