Чи є короткий і солодкий спосіб генерувати 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 : код, наведений у відповіді Дейва нижче. Технічно це не створює,
List<Integer>
а швидшеContiguousSet<Integer>
- але, оскільки воно реалізуєтьсяIterable<Integer>
по порядку, він здебільшого працює для моїх цілей. - intStreamRange : код, наведений у відповіді Володимира нижче, який використовує
IntStream.rangeClosed()
- який був введений в Java 8. - streamIterate : код, наведений у відповіді Каталіна нижче, який також використовує
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:
... і довжина = 10000:
Довга ітерація багатьох елементів збалансовує багато, але затемнення та гуава залишаються більш ніж удвічі швидшими навіть на тесті 10 000 елементів.
Отже, якщо ви дійсно хочете List<Integer>
, щоб колекції затемнення здавалися найкращим вибором - але, звичайно, якщо ви використовуєте потоки більш рідним способом (наприклад, забувши .boxed()
і зробите зменшення примітивного домену), ви, ймовірно, закінчитеся швидше, ніж усі ці варіанти.
1 Можливо, за винятком поводження з помилками, наприклад, якщо end
< begin
, або якщо розмір перевищує деякі обмеження на реалізацію або JVM (наприклад, масиви більше, ніж 2^31-1
.