Java-8中Stream的循环融合(内部如何工作)

Soh*_*Ahn 3 java java-8 java-stream

我正在读"Java in Action"一书.

我在书中看到了Stream的示例代码.

List<String> names = menu.stream()
                         .filter(d -> {
                                       System.out.println("filtering" + d.getName());
                                       return d.getCalories() > 300;
                                      })
                         .map(d -> {
                                    System.out.println("mapping" + d.getName());
                                    return d.getName();
                                    })
                         .limit(3)
                         .collect(toList());
Run Code Online (Sandbox Code Playgroud)

执行代码时,结果如下.

filtering __1__.
mapping __1__.
filtering __2__.
mapping __2__.
filtering __3__.
mapping __3__.
Run Code Online (Sandbox Code Playgroud)

也就是说,因为limit(3),日志消息只打印3次!在本书中,这被称为"循环融合".但是,我不明白这一点.因为,如果您知道对象是否已过滤,则必须计算过滤功能.然后,我认为应该打印"过滤......"信息.

请解释一下循环融合如何在内部工作.

Hol*_*ger 8

"因为,如果你[想要]知道一个对象是否被过滤,你必须计算过滤函数",是正确的,但也许你的样本数据不足以说明这一点.如果你试试

List<String> result = Stream.of("java", "streams", "are", "great", "stuff")
    .filter(s -> {
                  System.out.println("filtering " + s);
                  return s.length()>=4;
                 })
    .map(s -> {
               System.out.println("mapping " + s);
               return s.toUpperCase();
              })
    .limit(3)
    .collect(Collectors.toList());
System.out.println("Result:");
result.forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

它会打印出来

filtering java
mapping java
filtering streams
mapping streams
filtering are
filtering great
mapping great
Result:
JAVA
STREAMS
GREAT
Run Code Online (Sandbox Code Playgroud)

显示出来

  • 为了找到与过滤器匹配的三个元素,您可能必须评估三个以上的元素,这里评估了四个元素,但是一旦有三个匹配,则不需要评估后续元素

  • 后续映射函数只需要应用于匹配元素.这允许得出结论,这是无关紧要是否.map(…).limit(…).limit(…).map(…)指定.
    这与相对位置.filter.limit相关位置不同.

术语"循环融合"意味着没有过滤循环,接着是映射循环,后跟限制操作,但只有一个循环(概念上),执行整个工作,相当于以下单循环:

String[] source = { "java", "streams", "are", "great", "stuff"};
List<String> result = new ArrayList<>();
int limit = 3;
for(String s: source) {
    System.out.println("filtering " + s);
    if(s.length()>=4) {
        System.out.println("mapping " + s);
        String t = s.toUpperCase();
        if(limit-->0) {
            result.add(t);
        }
        else break;
    }
}
Run Code Online (Sandbox Code Playgroud)