一般问题:反转流的正确方法是什么?假设我们不知道流由什么类型的元素组成,那么反转任何流的通用方法是什么?
具体问题:
IntStream
提供在特定范围内生成整数的范围方法 IntStream.range(-range, 0)
,现在我想反转它,从 0 到负的切换范围将不起作用,我也不能使用 Integer::compare
List<Integer> list = Arrays.asList(1,2,3,4);
list.stream().sorted(Integer::compare).forEach(System.out::println);
与 IntStream
我会得到这个编译器错误
错误:(191, 0) ajc: 类型中的方法
sorted()
IntStream
不适用于参数 (Integer::compare
)
我在这里错过了什么?
原文由 vach 发布,翻译遵循 CC BY-SA 4.0 许可协议
对于生成反向
IntStream
的具体问题,尝试这样的事情:这避免了装箱和排序。
对于如何反转任何类型的流的一般问题,我不知道有什么“正确”的方法。我可以想到几种方法。两者最终都存储了流元素。我不知道有什么方法可以在不存储元素的情况下反转流。
第一种方法将元素存储到数组中,然后以相反的顺序将它们读出到流中。请注意,由于我们不知道流元素的运行时类型,因此我们无法正确键入数组,需要进行未经检查的转换。
另一种技术使用收集器将项目累积到反向列表中。这在
ArrayList
对象的前面做了很多插入,所以有很多复制正在进行。使用某种定制的数据结构编写一个更高效的反向收集器可能是可能的。
更新 2016-01-29
由于这个问题最近引起了一些关注,我想我应该更新我的答案以解决在
ArrayList
前面插入的问题。对于大量元素,这将是非常低效的,需要 O(N^2) 复制。最好使用
ArrayDeque
代替,它有效地支持在前面插入。一个小问题是我们不能使用Stream.collect()
的三参数形式;它要求将第二个 arg 的内容合并到第一个 arg 中,并且在Deque
上没有“add-all-at-front”批量操作。相反,我们使用addAll()
将第一个 arg 的内容附加到第二个 arg 的末尾,然后我们返回第二个。这需要使用Collector.of()
工厂方法。完整的代码是这样的:
结果是
Deque
而不是List
,但这应该不是什么大问题,因为它可以很容易地以现在相反的顺序迭代或流式传输。