Stream.of 和 IntStream.range 有什么区别?

Pav*_*l_K 52 java java-stream

请考虑以下代码:

System.out.println("#1");
Stream.of(0, 1, 2, 3)
        .peek(e -> System.out.println(e))
        .sorted()
        .findFirst();

System.out.println("\n#2");
IntStream.range(0, 4)
        .peek(e -> System.out.println(e))
        .sorted()
        .findFirst();
Run Code Online (Sandbox Code Playgroud)

输出将是:

#1
0
1
2
3

#2
0
Run Code Online (Sandbox Code Playgroud)

谁能解释一下,为什么两个流的输出不同?

Era*_*ran 51

嗯,IntStream.range()返回a sequential ordered IntStream from startInclusive(inclusive) to endExclusive (exclusive) by an incremental step of 1,这意味着它已经排序。既然已经排序了,那么下面的.sorted()中间操作什么都不做是有道理的。结果,peek()只在第一个元素上执行(因为终端操作只需要第一个元素)。

另一方面,传递给的元素Stream.of()不一定已排序(并且该of()方法不检查它们是否已排序)。因此,.sorted()必须遍历所有元素才能产生排序流,这允许findFirst()终端操作返回排序流的第一个元素。结果,peek对所有元素都执行,即使终端操作只需要第一个元素。

  • @ernest_k 1. 经过更多思考后,编译器优化似乎不太可能。我认为“或者至少什么也不做”部分更有可能是这种情况。2.您认为缺少哪方面的阐述?我在第二段写了为什么“sorted”通常需要遍历所有元素。 (4认同)
  • @ernest_k 它只是一个运行时优化,而且也有点脆弱 (4认同)
  • 两件事:1.这是编译器优化吗?看来你是这么暗示的。2. 如果您详细说明“sorted()”通过需要所有元素来产生差异(用于查看),将会很有帮助...很好的答案,顺便说一句。 (2认同)

Eug*_*ene 33

IntStream.range已经进行排序:

// reports true
System.out.println(
       IntStream.range(0, 4)
                .spliterator()
                .hasCharacteristics(Spliterator.SORTED)
);
Run Code Online (Sandbox Code Playgroud)

所以当sorted()Stream 上的方法被命中时,在内部,它会变成一个 NO-OP

否则,正如您在第一个示例中已经看到的那样,所有元素都必须排序,只有这样findFirst才能判断谁是“真正的第一个”。

请注意,此优化仅适用于自然排序的流。例如:

// prints too much you say?
Stream.of(new User(30), new User(25), new User(34))
            .peek(x -> System.out.println("1 : before I call first sorted"))
            .sorted(Comparator.comparing(User::age))
            .peek(x -> System.out.println("2 : before I call second sorted"))
            .sorted(Comparator.comparing(User::age))
            .findFirst();
Run Code Online (Sandbox Code Playgroud)

其中(为简洁起见):

record User(int age) { }
Run Code Online (Sandbox Code Playgroud)