Trying to represent a nested for loop as a Java Stream, but confused

Viewed 77

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 Answers

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