Home > Net >  Using Streams to replace loops
Using Streams to replace loops

Time:12-03

I have the following code:

boolean found = false;
for (Commit commit : commits.values()) {
    if (commit.getLogMessage().compareTo(commitMessageToSearch) == 0) {
        System.out.println(commit.getSha());
        found = true;
    }
}
if (!found) {
    System.out.println("aksdhlkasj");
}

Is there some way to write this succinctly using streams or anything else in Java

CodePudding user response:

You can use Stream#filter along with Stream#findFirst.

System.out.println(commits.values().stream()
    .filter(commit -> commit.getLogMessage().compareTo(commitMessageToSearch) == 0)
    .findFirst().map(Commit::getSha).orElse("aksdhlkasj"));

CodePudding user response:

As there is a "state" that needs to be checked outside the loop, a stream-based solution using Stream::forEach would set found value outside the stream and therefore is not pure but it prints all filtered SHA codes as the for-loop version:

AtomicBoolean found = new AtomicBoolean(); // effectively final container boolean

commits.values().stream()
    .filter(commit -> commit.getLogMessage().compareTo(commitMessageToSearch) == 0)
    .map(Commit::getSha)
    .forEach(sha -> {
        found.set(true); 
        System.out.println(sha);
    });

if (!found.get()) {
    System.out.println("none found");
}

Or use short-circuiting Stream::anyMatch to check if the filtered stream contains at least one matching entry:

if (commits.values().stream()
    .map(Commit::getLogMessage) // equals should be equivalent to compareTo == 0
    .anyMatch(commitMessageToSearch::equals))
{
    commits.values().stream()
        .filter(commit -> commit.getLogMessage().compareTo(commitMessageToSearch) == 0)
        .map(Commit::getSha)
        .forEach(System.out::println);
} else {
    System.out.println("none found");
}

But this is definitely more verbose than for-loop solution.

  • Related