Existe uma maneira curta e agradável de gerar um List<Integer>
, ou talvez um Integer[]
ou int[]
, com valores seqüenciais de algum start
valor para um end
valor?
Ou seja, algo menor que, mas equivalente a 1 o seguinte:
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;
}
O uso de goiaba é bom.
Atualizar:
Análise de desempenho
Como esta pergunta recebeu várias boas respostas, usando bibliotecas Java 8 nativas e de terceiros, pensei em testar o desempenho de todas as soluções.
O primeiro teste simplesmente testa a criação de uma lista de 10 elementos [1..10]
usando os seguintes métodos:
- classicArrayList : o código fornecido acima na minha pergunta (e essencialmente o mesmo que a resposta de adarshr).
- eclipseCollections : o código fornecido na resposta de Donald abaixo usando o Eclipse Collections 8.0.
- guavaRange : o código fornecido na resposta daveb abaixo. Tecnicamente, isso não cria um,
List<Integer>
mas sim umContiguousSet<Integer>
- mas, como é implementadoIterable<Integer>
em ordem, funciona principalmente para meus propósitos. - intStreamRange : o código fornecido na resposta de Vladimir abaixo, que usa
IntStream.rangeClosed()
- que foi introduzido no Java 8. - streamIterate : o código fornecido na resposta do Catalin abaixo, que também usa a
IntStream
funcionalidade introduzida no Java 8.
Aqui estão os resultados em operações de quilo por segundo (números maiores são melhores), para todos os itens acima com listas de tamanho 10:
... e novamente para listas de tamanho 10.000:
Esse último gráfico está correto - as soluções que não sejam Eclipse e Guava são muito lentas para obter uma única barra de pixels! As soluções rápidas são 10.000 a 20.000 vezes mais rápidas que as demais.
O que está acontecendo aqui, é claro, é que as soluções goiaba e eclipse realmente não materializam nenhum tipo de lista de 10.000 elementos - elas são simplesmente invólucros de tamanho fixo em torno do ponto inicial e final. Cada elemento é criado conforme necessário durante a iteração. Como na verdade não iteramos neste teste, o custo é adiado. Todas as outras soluções, na verdade, materializam a lista completa na memória e pagam um preço muito alto em uma referência apenas para criação.
Vamos fazer algo um pouco mais realista e também iterar sobre todos os números inteiros, somando-os. Portanto, no caso da IntStream.rangeClosed
variante, a referência se parece com:
@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;
}
Aqui, as imagens mudam bastante, embora as soluções não materializantes ainda sejam as mais rápidas. Aqui está o comprimento = 10:
... e comprimento = 10.000:
A longa iteração sobre muitos elementos equilibra bastante as coisas, mas o eclipse e a goiaba permanecem mais que o dobro da velocidade, mesmo no teste de 10.000 elementos.
Portanto, se você realmente deseja List<Integer>
, coleções de eclipses parece ser a melhor escolha - mas é claro que se você usar fluxos de maneira mais nativa (por exemplo, esquecendo .boxed()
e fazendo uma redução no domínio primitivo), provavelmente terminará mais rápido do que todos esses variantes.
1 Talvez, com exceção do tratamento de erros, por exemplo, se end
< begin
, ou se o tamanho exceder alguns limites de implementação ou JVM (por exemplo, matrizes maiores que 2^31-1
.