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

2022-08-31 20:14:12

请考虑以下代码:

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

输出将为:

#1
0
1
2
3

#2
0

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


答案 1

好吧,返回 ,这意味着它已经排序了。由于它已排序,因此以下中间操作不执行任何操作是有道理的。结果,仅在第一个元素上执行(因为终端操作只需要第一个元素)。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


答案 2

IntStream.range排序:

// reports true
System.out.println(
       IntStream.range(0, 4)
                .spliterator()
                .hasCharacteristics(Spliterator.SORTED)
);

因此,当流上的方法被击中时,在内部,它将变成NO-OPsorted()

否则,正如您在第一个示例中已经看到的那样,所有元素都必须进行排序,只有这样才能分辨出谁是“真正的第一个”。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();

其中(为简洁起见):

record User(int age) { }

推荐