简体   繁体   English

使用 Streams 替换循环

[英]Using Streams to replace loops

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 有什么方法可以简洁地使用流或 Java 中的其他任何东西来编写这个

You can use Stream#filter along with Stream#findFirst .您可以将Stream#filterStream#findFirst一起使用。

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

Just replacing your logic with stream functionality, using lambda expression只需使用 lambda 表达式用 stream 功能替换您的逻辑

    boolean found = false;
    
    commits.values().stream().filter(c -> 
    c.getLogMessage().compareTo(commitMessageToSearch) == 0).forEach(c -> {
    System.out.println(c.getSha());
    found = true;
    });
    
    if (!found) {
        System.out.println("aksdhlkasj");
    }

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:由于需要在循环外检查“状态”,因此使用Stream::forEach的基于流的解决方案将在 stream 之外设置found的值,因此不是纯的,但它会将所有过滤的 SHA 代码打印为for-loop版本:

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:或者使用短路Stream::anyMatch来检查过滤后的 stream 是否包含至少一个匹配条目:

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.但这绝对比for-loop解决方案更冗长。

You want this:你要这个:

commits.values()
       .stream()
       .filter(commit -> commit.getLogMessage().compareTo(commitMessageToSearch) == 0)
       .findFirst()
       .map(Commit::getSha)
       .ifPresentOrElse(
               System.out::println,                      // if present, print out sha
               () -> System.out.println("aksdhlkasj"));  // print some garbage otherwise

Basically, you filter out the unwanted commits.基本上,您过滤掉不需要的提交。 Once you find a correct one, the method Stream#findfirst short-circuits the processing as long as there is no need to search further.一旦找到正确的,只要不需要进一步搜索,方法Stream#findfirst就会使处理短路。 For that reason, you might want to add break in your for a loop.因此,您可能希望在 for 循环中添加break Finally, extract sha from the Commit using Optional#map and then Optional#ifPresentOrElse handles both situation if such commit is present or not.最后,使用Optional#mapCommit中提取sha ,然后Optional#ifPresentOrElse处理这两种情况,无论是否存在此类提交。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM