Stream.of和IntStream.range有什么区别?
请考虑以下代码:
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
谁能解释一下,为什么两个流的输出不同?
回答
嗯,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. After thinking about it more, compiler optimization seems less likely. I think the `or at least does nothing` part is more likely to be the case. 2. what kind of elaboration do you think is missing? I wrote in the second paragraph why `sorted` usually needs to traverse all the elements.
- @ernest_k it is a runtime optimization only, and a bit fragile too
- 2 things: 1. is this a compiler optimization? seems like you imply that. 2. Would be helpful if you elaborate on `sorted()` making a difference (for peek) by needing all elements... Good answer, btw.
回答
IntStream.range在已经进行排序:
// reports true
System.out.println(
IntStream.range(0, 4)
.spliterator()
.hasCharacteristics(Spliterator.SORTED)
);
所以当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();
其中(为简洁起见):
record User(int age) { }