Использование потока для повторения n раз вместо использования цикла for для создания n элементов

Скажем, я хочу создать n элементов. Pre Java 8, я бы написал:

List<MyClass> list = new ArrayList<>();
for (int i = 0; i < n; i++) {
    list.add(new MyClass());
}

Есть ли элегантный способ использования потока для создания n элементов?
Я подумал об этом:

List<MyClass> list = Stream.iterate(0, i -> i).limit(10)
    .map(o -> new MyClass()).collect(Collectors.toList());

Есть ли стандартный/лучший способ кодирования этого?

Обратите внимание, что фактическое использование немного сложнее, и использование потока будет более гибким, потому что я могу сразу перекачать элементы через другие функции в одной строке, даже не создавая ссылку на список, например, группируя их:

Stream.iterate(0, i -> i).limit(10).map(o -> new MyClass())
    .collect(Collectors.groupingBy(...));

Ответы

Ответ 1

Вы можете использовать Stream#generate с limit:

Stream.generate(MyClass::new).limit(10);

Ответ 2

Если вы знаете n заранее, я думаю, что более идиоматично использовать один из источников потока, который создает поток, который, как известно, имеет ровно n элементов. Несмотря на появление, использование limit(10) не обязательно приводит к потоку SIZED с ровно 10 элементами - его может быть меньше. Наличие потока SIZED улучшает расщепление в случае параллельного выполнения.

Как отметил в комментарии Sotirios Delimanolis, вы можете сделать что-то вроде этого:

List<MyClass> list = IntStream.range(0, n)
    .mapToObj(i -> new MyClass())
    .collect(toList());

Альтернативой является это, хотя мне это не ясно, лучше:

List<MyClass> list2 = Collections.nCopies(10, null).stream()
    .map(o -> new MyClass())
    .collect(toList());

Вы также можете сделать это:

List<MyClass> list = Arrays.asList(new MyClass[10]);
list.replaceAll(o -> new MyClass());

Но это приводит к списку фиксированного размера, но изменяемому.