Есть ли простой и приятный способ сгенерировать 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, так и сторонних библиотек, я подумал, что протестирую производительность всех решений.
Первый тест просто тестирует создание списка из 10 элементов [1..10]
с использованием следующих методов:
- classicArrayList : код, приведенный выше в моем вопросе (и, по сути, такой же, как ответ adarshr).
- eclipseCollections : код, указанный в ответе Дональда ниже с использованием Eclipse Collections 8.0.
- guavaRange : код, указанный в ответе daveb ниже. Технически это создает не a,
List<Integer>
а скорееContiguousSet<Integer>
- но, поскольку он реализуетсяIterable<Integer>
по порядку, он в основном работает для моих целей. - intStreamRange : код, приведенный в ответе Владимира ниже, который использует
IntStream.rangeClosed()
- который был введен в Java 8. - streamIterate : код, приведенный в ответе Каталина ниже, который также использует
IntStream
функции, представленные в Java 8.
Вот результаты в килограммах операций в секунду (чем больше, тем лучше), для всего вышеперечисленного со списками размером 10:
... и снова для списков размером 10 000:
Последняя диаграмма верна - решения, отличные от Eclipse и Guava, слишком медленные, чтобы получить даже полосу в один пиксель! Быстрые решения в 10–20 000 раз быстрее остальных.
Конечно, здесь происходит то, что решения guava и 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 элементов.
Так что, если вы действительно хотите List<Integer>
, коллекции eclipse кажутся лучшим выбором, но, конечно, если вы используете потоки более естественным способом (например, забывая .boxed()
и сокращая примитивный домен), вы, вероятно, закончите быстрее, чем все эти варианты.
1 Возможно, за исключением обработки ошибок, например, если end
< begin
, или если размер превышает некоторые ограничения реализации или JVM (например, массивы больше, чем 2^31-1
.