Есть ли разница в производительности в toArray против stream.toArray в Java? - PullRequest
3 голосов
/ 29 марта 2019

Мне нужно преобразовать список идентификаторов в массив идентификаторов. Я могу сделать это разными способами, но не уверен, какой из них следует использовать.

Say,

1. ids.stream().toArray(Id[]::new)
2. ids.toArray(new Id[ids.length])

Какой из них более эффективен и почему?

1 Ответ

5 голосов
/ 29 марта 2019

Java-11 представил Collection::toArray, который имеет эту реализацию:

default <T> T[] toArray(IntFunction<T[]> generator) {
    return toArray(generator.apply(0));
}

Чтобы сделать его проще в вашем случае, он на самом деле делает: ids.toArray(new Id[0]); то есть - он не указывает общий ожидаемый размер.

Это быстрее, чем указание размера, и это не интуитивно понятно; но это связано с тем фактом, что если JVM может доказать, что выделенный вами массив будет переопределен с помощью некоторого копирования, которое следует сразу же, ему не нужно выполнять начальное обнуление массива, и это оказывается быстрее, чем указание начального размера (где должно происходить обнуление).

Потоковый подход будет иметь (или пытаться угадать оценку) начальный размер, который будет вычисляться внутренними компонентами потока, потому что:

 ids.stream().toArray(Id[]::new)

на самом деле:

 ids.stream().toArray(size -> Id[size]);

и что size является либо известным, либо оценочным, исходя из внутренних характеристик, которыми обладает Spliterator. Если поток сообщает характеристику SIZED (как в вашем простом случае), то все просто, size всегда известен. С другой стороны, если этого SIZED нет, внутренние компоненты потока будут иметь только оценку того, сколько элементов будет присутствовать, и в таком случае для сбора элементов будет использоваться скрытая новая коллекция, называемая SpinedBuffer.

Вы можете прочитать больше здесь , но подход ids.toArray(new Id[0]) будет самым быстрым.

...