有没有产生一个简短而亲切的方式List<Integer>
,或者可能是 Integer[]
或int[]
,与一些连续值start
值的end
价值?
也就是说,以下内容比以下内容短,但等于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;
}
番石榴的用途很好。
更新:
绩效分析
由于使用本机Java 8和第三方库都可以很好地回答这个问题,所以我认为我应该测试所有解决方案的性能。
第一个测试只是[1..10]
使用以下方法测试创建包含10个元素的列表:
- classicArrayList:我问题中上面给出的代码(与adarshr的回答基本相同)。
- eclipseCollections:下面的Donald答案中使用Eclipse Collections 8.0 给出的代码。
- guavaRange:下面的daveb答案中给出的代码。从技术上讲,这并不会创建
List<Integer>
而是ContiguousSet<Integer>
-,但是由于它Iterable<Integer>
是按顺序实现的,因此大多数情况下可以实现我的目的。 - intStreamRange:下面弗拉基米尔的答案中给出的代码,它使用
IntStream.rangeClosed()
-在Java 8中引入的。 - streamIterate:下面的Catalin答案中给出的代码,该代码也使用
IntStream
Java 8中引入的功能。
以下是上述所有大小为10的列表的结果,以千千克/秒为单位(数字越大越好):
...再一次列出大小为10,000的列表:
最后一张图表是正确的-除Eclipse和Guava之外的解决方案太慢,甚至无法获得单个像素条!快速的解决方案是其他解决方案的10,000到20,000 倍。
当然,这里发生的是番石榴和日食解决方案实际上并没有实现任何类型的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个元素测试时,日食和番石榴的速度仍是其两倍以上。
因此,如果您真的想要List<Integer>
,eclipse集合似乎是最佳选择-但是,如果您以更原生的方式使用流(例如,忘记.boxed()
并进行原始域的缩减),则最终可能会比所有这些更快变体。
1也许是错误处理的例外,例如,如果end
< begin
,或者大小超过某些实现或JVM限制(例如,大于的数组)2^31-1
。