是否有一种简短而甜蜜的方法来生成一个 List<Integer>
,或者可能是一个 Integer[]
或 int[]
,其中包含从某个 start
值到一个 end
值的连续值?
也就是说,比下面的 1要短,但相当于 1:
void List<Integer> makeSequence(int begin, int end) {
List<Integer> ret = new ArrayList<>(end - begin + 1);
for (int i=begin; i<=end; i++) {
ret.add(i);
}
return ret;
}
番石榴的用途是罚款。
更新:
由于这个问题已经得到了一些很好的回答,包括使用本地 Java8和第三方库,因此我认为应该测试所有解决方案的性能。
第一个测试使用以下方法简单地测试创建一个包含10个元素的 [1..10]
列表:
List<Integer>
,而是一个 ContiguousSet<Integer>
-但是因为它按顺序实现了 Iterable<Integer>
,所以它基本上可以满足我的目的。IntStream.rangeClosed()
-。IntStream
功能。下面是每秒千次运算的结果(数字越大越好) ,适用于上面所有大小为10的列表:
还有10000码的单子:
最后一张图表是正确的—— Eclipse 和 Guava 之外的解决方案都太慢了,甚至连一个像素条都没有!快速解决方案比其他方案快10,000到20,000个 时间。
当然,这里发生的事情是,番石榴和 eclipse 解决方案实际上并没有实现任何类型的10,000元素列表——它们只是围绕起始点和终结点的固定大小的包装器。每个元素都是在迭代过程中根据需要创建的。由于我们实际上并没有在这个测试中迭代,因此成本被推迟了。所有其他解决方案实际上都在内存中实现了完整的列表,并且在仅创建基准中付出了沉重的代价。
让我们做一些更实际的事情,并且对所有的整数进行迭代,求和。因此,在 IntStream.rangeClosed
变体的情况下,基准看起来是这样的:
@Benchmark
public int intStreamRange() {
List<Integer> ret = IntStream.rangeClosed(begin, end).boxed().collect(Collectors.toList());
int total = 0;
for (int i : ret) {
total += i;
}
return total;
}
在这里,图片变化很大,虽然非物质化的解决方案仍然是最快的。这里的长度 = 10:
... 和长度 = 10,000:
对许多元素的长时间迭代使事情变得更加平衡,但是即使在10,000个元素的测试中,Eclipse 和番石榴的速度仍然是原来的两倍以上。
所以如果你想使用 List<Integer>
,Eclipse 集合看起来是最好的选择——当然,如果你以一种更原生的方式使用流(例如,忘记 .boxed()
并在原始域中做一个简化) ,你可能会比所有这些变体更快结束。
也许除了错误处理,例如,如果 end
< begin
,或者如果大小超过一些实现或 JVM 限制(例如,数组大于 2^31-1
。